问题 完整的GC变得非常频繁


我在一个tomcat实例上运行了一个Java webapp。在高峰时段,webapp每秒大约30页,通常大约15页。

我的环境是:

O/S: SUSE Linux Enterprise Server 10 (x86_64)
RAM: 16GB

server: Tomcat 6.0.20
JVM: Java HotSpot(TM) 64-Bit Server VM 1.6.0_14
JVM options:
CATALINA_OPTS="-Xms512m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=256m
               -XX:+UseParallelGC
               -Djava.awt.headless=true
               -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps"
JAVA_OPTS="-server"

经过几天的正常运行后,Full GC开始更频繁地发生,并且它成为应用程序可用性的严重问题。在tomcat重新启动之后,问题就会消失,但当然会在5到10天或30天后返回(不一致)。

重启前后的完整GC日志为 http://pastebin.com/raw.php?i=4NtkNXmi

它显示重启之前的日志,在6.6天的正常运行时间,因为完整的GC需要2.5秒,并且每隔约6秒发生一次。

然后它会在重启后显示一个日志,其中Full GC仅每5-10分钟发生一次。

我有两个转储使用 jmap -dump:format=b,file=dump.hprof PID 当Full GC发生时(我不确定在完全GC发生时或两个完整GC之间是否完全正确)并打开它们 http://www.eclipse.org/mat/ 但在泄漏嫌疑人中没有得到任何有用的东西:

  • 60MB:“org.hibernate.impl.SessionFactoryImpl”的1个实例(我使用带有ehcache的hibernate)
  • 80MB:1,024个“org.apache.tomcat.util.threads.ThreadWithAttributes”实例(这些可能是tomcat的1024个工作者)
  • 45MB:37个“net.sf.ehcache.store.compound.impl.MemoryOnlyStore”实例(这些应该是我在ehcache中的~37个缓存区域)

请注意,我从未得到OutOfMemoryError。

关于我下一步应该去哪看的任何想法?


5242
2017-10-27 13:40


起源

如果服务器上有16GB的RAM,为什么不使用更大的最大堆大小(-Xmx)? - matt b
我从来没有得到过OutOfMemoryError所以我认为,因为应用程序可以运行然后它没关系。另外,我已经读过,给JVM提供太多内存将使Full GC变慢。真的吗? - cherouvim
你能在测试环境中重现这种行为吗?也许有一些负载测试。我以前调试过这样的行为,但通常有很多来自探查器的帮助(它会在生产环境中杀死你的服务器)。 - pcalcao
还有@cherouvim你见过吗? oracle.com/technetwork/java/javase/gc-tuning-6-140523.html ?可能会有所帮助。 - matt b
“我从未得到过OutOfMemoryError” - 不是 所有 使用内存但是正在发生完整的GC,因为旧一代已满。分配更多的内存将使年轻人的对象保持更长时间 - 更有可能被次要收集清理/不太可能被提升。 - symcbean


答案:


当我们遇到这个问题时,我们最终将它追溯到年轻一代太小了。虽然我们已经给了很多公羊,但年轻一代却没有得到公平的分享。

这意味着小垃圾收集会更频繁地发生,并导致一些年轻的对象被移动到tenured generation,这意味着更大的垃圾收集。

尝试使用 -XX:NewRatio 具有相当低的值(比如2或3),看看这是否有帮助。

可以找到更多信息 这里


6
2017-10-27 14:06





我已经改变了 -Xmx1024m 至 -Xmx2048m 问题就消失了。我现在有100天的正常运行时间。


4
2017-10-26 10:53





在你的情况下可能会发生的事情是你有很多物体比NewGen生命周期长一点。如果幸存者空间太小,他们会直接进入OldGen。 -XX:+PrintTenuringDistribution 可以提供一些见解。你的NewGen足够大,所以试着减少 SurvivorRatio

此外,jconsole可能会提供更多关于你的记忆发生情况的视觉洞察,尝试一下。


3
2017-10-27 17:07





除了调整JVM的各种选项之外,我还建议升级到VM的更新版本,因为后期版本具有更好的调优垃圾收集器(也没有尝试新的实验版)。

除此之外,如果(部分)确定为JVM分配更多内存可能会增加执行GC所需的时间,那么在使用整个16 GB内存和增加内存占用之间存在权衡点,因此您可以尝试将所有值加倍,开始

Xms1024m -Xmx2048m -XX:PermSize = 256m -XX:MaxPermSize = 512m

问候

马西莫


2
2017-10-27 14:15



我会尽力。但是maxperm 512不是太多了吗? tomcat实例只运行1个应用程序,包含大约40个持久(hibernate)实体,没有spring框架。没有重新部署在这个tomcat上,只有关闭/启动。 - cherouvim
可能是,我建议的参数只是一个简单的猜测。我会指出更新JVM是一个更好的尝试,我们有类似的问题(以及其他的),当我们更新Java更新27时它们就消失了。最新的更新29但是我们遇到了一些问题。 - massimogentilini
是的,日志显示大约64MB的PSPermGen,我猜是JVM,tomcat,库和我的应用程序的总加载类大小。对? - cherouvim
好的,也会更新JVM。谢谢。 - cherouvim