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

时间:2010-03-15 16:59:47

标签: java garbage-collection jvm memory-management out-of-memory

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

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

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

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

无论如何,我不想自己监视我的jvm的内存分配(或者将内存管理插入到我的应用程序的逻辑中);如果有一种方法可以运行具有内存阈值的虚拟机,那么将会自动执行完整的GC,以便尽快释放我需要的内存。

长话短说:我需要一种方法(命令行选项?)来配置jvm,以便在内存占用达到某个阈值时提前释放大量内存(即执行完整的GC),我不知道如果这会在一段时间内减慢我的应用程序,请小心。

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

我很感激你的建议,

西尔维奥

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

更新:使用jvisualvm分析应用,我可以看到问题出在老一代

7 个答案:

答案 0 :(得分:7)

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

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

-XX:CMSInitiatingOccupancyFraction=<percent>

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

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

答案 1 :(得分:4)

当您分配不适合年轻一代的大型对象时,它们会立即分配到终身生成空间中。当您尝试强制运行全GC时,此空间仅为GC。

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

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

你说“当内存占用达到某个阈值时,我需要一种方法尽早释放大量内存(即执行完整的GC)”。如果你的应用程序中的任何东西都没有引用“大量内存”,那么这个定义只能成功。

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

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

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

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

有关GC如何工作here的非常详细的解释,它列出了控制可用于不同内存池/代的内存的参数。

答案 4 :(得分:1)

在尝试通过垃圾收集释放内存之后,JVM只能抛出OutOfMemoryError (根据the API docs for OutOfMemoryErrorthe JVM specification)。因此,您强制垃圾收集的尝试应该没有任何区别。所以这里可能会有一些更重要的事情 - 你的程序没有正确清除引用的问题,或者不太可能发生JVM错误。

答案 5 :(得分:0)

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

答案 6 :(得分:0)

你试过玩G1 gc吗?它应该在1.6.0u14开始提供。