java 当内存占用超过某个阈值时强制完全垃圾回收

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2448941/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 21:12:45  来源:igfitidea点击:

Force full garbage collection when memory occupation goes beyond a certain threshold

javagarbage-collectionjvmmemory-managementout-of-memory

提问by Silvio Donnini

I have a server application that, in rare occasions, can allocate large chunks of memory.

我有一个服务器应用程序,在极少数情况下,它可以分配大块内存。

It's not a memory leak, as these chunks can be claimed back by the garbage collector by executing a full garbage collection. Normal garbage collection frees amounts of memory that are too small: it is not adequate in this context.

这不是内存泄漏,因为垃圾收集器可以通过执行完整的垃圾收集来收回这些块正常的垃圾回收释放的内存量太小:在这种情况下是不够的。

The garbage collector executes these full GCs when it deems appropriate, namely when the memory footprint of the application nears the allotted maximum specified with -Xmx.

垃圾收集器在它认为合适的时候执行这些完整的 GC,即当应用程序的内存占用接近 -Xmx 指定的分配最大值时。

That would be ok, if it wasn't for the fact that these problematic memory allocations come in bursts, and can cause OutOfMemoryErrors due to the fact that the jvm is not able to perform a GC quickly enough to free the required memory. If I manually call System.gc() beforehand, I can prevent this situation.

没关系,如果不是因为这些有问题的内存分配突然出现,并且由于jvm 无法足够快地执行 GC 以释放所需内存而导致 OutOfMemoryErrors 。如果我事先手动调用 System.gc(),我可以防止这种情况。

Anyway, I'd prefer not having to monitor my jvm's memory allocation myself (or insert memory management into my application's logic); it would be nice if there was a way to run the virtual machine with a memory threshold, over which full GCs would be executed automatically, in order to release very early the memory I'm going to need.

无论如何,我宁愿不必自己监视 jvm 的内存分配(或将内存管理插入到我的应用程序逻辑中);如果有一种方法可以运行具有内存阈值的虚拟机,在该阈值之上将自动执行完整的 GC,以便尽早释放我将需要的内存,那就太好了。

Long story short: I need a way (a command line option?) to configure the jvm in order to release early a good amount of memory (i.e. perform a full GC) when memory occupation reaches a certain threshold, I don't care if this slows my application down every once in a while.

长话短说:我需要一种方法(命令行选项?)来配置 jvm,以便在内存占用达到某个阈值时尽早释放大量内存(即执行完整的 GC),我不在乎这会时不时地减慢我的应用程序的速度。

All I've found till now are ways to modify the size of the generations, but that's not what I need (at least not directly).

到目前为止,我发现的只是修改世代大小的方法,但这不是我需要的(至少不是直接需要的)。

I'd appreciate your suggestions,

我会很感激你的建议

Silvio

西尔维奥

P.S. I'm working on a way to avoid large allocations, but it could require a long time and meanwhile my app needs a little stability

PS 我正在努力避免大量分配,但这可能需要很长时间,同时我的应用程序需要一点稳定性

UPDATE: analyzing the app with jvisualvm, I can see that the problem is in the old generation

更新:用jvisualvm分析app,发现问题出在老年代

采纳答案by Sbodd

From here(this is a 1.4.2 page, but the same option should exist in all Sun JVMs):

这里开始(这是一个 1.4.2 页面,但所有 Sun JVM 中都应该存在相同的选项):

assuming you're using the CMS garbage collector (which I believe the server turns on by default), the option you want is

假设您正在使用 CMS 垃圾收集器(我相信服务器默认打开),您想要的选项是

-XX:CMSInitiatingOccupancyFraction=<percent>

where % is the % of memory in use that will trigger a full GC.

其中 % 是将触发完整 GC 的正在使用内存的百分比。

Insert standard disclaimers here that messing with GC parameters can give you severe performance problems, varies wildly by machine, etc.

在此处插入标准的免责声明,即弄乱 GC 参数会给您带来严重的性能问题,因机器而异,等等。

回答by Daniel Schneller

When you allocate large objects that do not fit into the young generation, they are immediately allocated in the tenured generation space. This space is only GC'ed when a full-GC is run which you try to force.

当您分配不适合年轻代的大对象时,它们会立即分配到年老代空间中。只有在您尝试强制运行 full-GC 时,才会对这个空间进行 GC。

However I am not sure this would solve your problem. You say "JVM is not able to perform a GC quickly enough". Even if your allocations come in bursts, each allocation will cause the VM to check if it has enough space available to do it. If not - and if the object is too large for the young generation - it will cause a full GC which should "stop the world", thereby preventing new allocations from taking place in the first place. Once the GC is complete, your new object will be allocated.

但是我不确定这会解决您的问题。您说“JVM 无法足够快地执行 GC”。即使您的分配是突发的,每次分配都会导致 VM 检查它是否有足够的可用空间来执行此操作。如果不是 - 如果对象对于年轻代来说太大 - 它将导致完整的 GC 应该“停止世界”,从而首先阻止新的分配发生。GC 完成后,您的新对象将被分配。

If shortly after that the second large allocation is requested in your burst, it will do the same thing again. Depending on whether the initial object is still needed, it will either be able to succeed in GC'ing it, thereby making room for the next allocation, or fail if the first instance is still referenced.

如果此后不久在您的突发中请求第二个大分配,它将再次执行相同的操作。根据是否仍然需要初始对象,它要么能够成功地对其进行 GC,从而为下一次分配腾出空间,要么在第一个实例仍被引用时失败。

You say "I need a way [...] to release early a good amount of memory (i.e. perform a full GC) when memory occupation reaches a certain threshold". This by definition can only succeed, if that "good amount of memory" is not referenced by anything in your application anymore.

您说“当内存占用达到某个阈值时,我需要一种方法 [...] 来提前释放大量内存(即执行完整的 GC)”。如果您的应用程序中的任何内容不再引用“大量内存”,那么根据定义,这只能成功。

From what I understand here, you might have a race condition which you might sometimes avoid by interspersing manual GC requests. In general you should never have to worry about these things - from my experience an OutOfMemoryError only occurs if there are in fact too many allocations to be fit into the heap concurrently. In all other situations the "only" problem should be a performance degradation (which might become extreme, depending on the circumstances, but this is a different problem).

根据我在这里的理解,您可能会遇到竞争条件,有时您可以通过穿插手动 GC 请求来避免这种情况。一般来说,您永远不必担心这些事情 - 根据我的经验,只有在实际上有太多分配无法同时放入堆时才会发生 OutOfMemoryError。在所有其他情况下,“唯一”问题应该是性能下降(这可能会变得极端,取决于具体情况,但这是一个不同的问题)。

I suggest you do further analysis of the exact problem to rule this out. I recommend the VisualVM tool that comes with Java 6. Start it and install the VisualGC plugin. This will allow you to see the different memory generations and their sizes. Also there is a plethora of GC related logging options, depending on which VM you use. Some options have been mentioned in other answers.

我建议您对确切问题进行进一步分析以排除这种情况。我推荐Java 6 自带的VisualVM 工具。启动它并安装VisualGC 插件。这将允许您查看不同的内存代及其大小。还有大量与 GC 相关的日志记录选项,具体取决于您使用的 VM。其他答案中已经提到了一些选项。

The other options for choosing which GC to use and how to tweak thresholds should not matter in your case, because they all depend on enough memory being available to contain all the objects that your application needs at any given time. These options can be helpful if you have performance problems related to heavy GC activity, but I fear they will not lead to a solution in your particular case.

选择使用哪个 GC 以及如何调整阈值的其他选项在您的情况下应该无关紧要,因为它们都取决于有足够的可用内存来包含您的应用程序在任何给定时间需要的所有对象。如果您遇到与大量 GC 活动相关的性能问题,这些选项可能会有所帮助,但我担心它们不会在您的特定情况下找到解决方案。

Once you are more confident in what is actually happening, finding a solution will become easier.

一旦您对实际发生的事情更有信心,找到解决方案就会变得更容易。

回答by Dan Dyer

The JVM is only supposed to throw an OutOfMemoryErrorafterit has attempted to release memory via garbage collection (according to both the API docs for OutOfMemoryErrorand the JVM specification). Therefore your attempts to force garbage collection shouldn't make any difference. So there might be something more significant going on here - either a problem with your program not properly clearing references or, less likely, a JVM bug.

JVM 只应该OutOfMemoryError它尝试通过垃圾收集释放内存抛出一个(根据OutOfMemoryError 的 API 文档JVM 规范)。因此,您尝试强制垃圾收集应该没有任何区别。所以这里可能有一些更重要的事情发生——要么是你的程序没有正确清除引用的问题,要么是 JVM 错误(不太可能)。

回答by James B

Do you know which of the garbage collection pools are growing too large?....i.e. eden vs. survivor space? (try the JVM option -Xloggc:<file> log GC status to a file with time stamps)...When you know this, you should be able to tweak the size of the effected pool with one of the options mentioned here: hotspot options for Java 1.4

你知道哪些垃圾收集池变得太大了吗?....即伊甸园与幸存者空间?(尝试 JVM 选项-Xloggc:<file> log GC status to a file with time stamps)...当您知道这一点时,您应该能够使用此处提到的选项之一调整受影响池的大小:Java 1.4 的热点选项

I know that page is for the 1.4 JVM, I can't seem to find the same -X options on my current 1.6 install help options, unless setting those individual pool sizes is a non-standard, non-standard feature!

我知道该页面适用于 1.4 JVM,我似乎无法在当前的 1.6 安装帮助选项中找到相同的 -X 选项,除非设置这些单独的池大小是非标准的非标准功能!

回答by Tomislav Nakic-Alfirevic

There's a very detailed explanation of how GC works hereand it lists parameters to control memory available to different memory pools/generations.

还有的GC是如何工作的一个非常详细的解释在这里,它列出了可用于不同的内存池/代参数,以控制存储器。

回答by Artic

Try to use -server option. It will enable parallel gc and you will have some performance increase if you use multi core processor.

尝试使用 -server 选项。它将启用并行 gc,如果您使用多核处理器,您将获得一些性能提升。

回答by mindas

Have you tried playing with G1 gc? It should be available in 1.6.0u14 onwards.

你试过玩 G1 gc 吗?它应该在 1.6.0u14 以后可用。