Java 无明显原因的终身托收
我有一个Java应用程序,它通常具有非常健康的垃圾收集统计数据。长期收集通常每小时左右进行一次,STW部分只需几分之一秒。但奇怪的是,收集总是在应用程序启动的前五分钟内发生。这是一个真正的问题,因为在那个时候,CPU的使用率已经远远高于正常水平(由于网络调用的增加,最终会被缓存),所以这些暂停时间总是比正常时间长,如果我在非常重的负载下重新启动,甚至会超过8秒 以下是JVM参数:Java 无明显原因的终身托收,java,garbage-collection,Java,Garbage Collection,我有一个Java应用程序,它通常具有非常健康的垃圾收集统计数据。长期收集通常每小时左右进行一次,STW部分只需几分之一秒。但奇怪的是,收集总是在应用程序启动的前五分钟内发生。这是一个真正的问题,因为在那个时候,CPU的使用率已经远远高于正常水平(由于网络调用的增加,最终会被缓存),所以这些暂停时间总是比正常时间长,如果我在非常重的负载下重新启动,甚至会超过8秒 以下是JVM参数: -Xms4096m -Xmx4096m -XX:PermSize=768m -XX:MaxPermSize=7
-Xms4096m
-Xmx4096m
-XX:PermSize=768m
-XX:MaxPermSize=768m
-XX:SurvivorRatio=6
-XX:NewSize=1024m
-verbose:gc
-XX:-DisableExplicitGC
-XX:+PrintGCDetails
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-XX:+PrintTenuringDistribution
-XX:+HeapDumpOnOutOfMemoryError
-XX:MaxDirectMemorySize=2048m
-XX:+UseConcMarkSweepGC
-XX:+CMSClassUnloadingEnabled
-XX:+PrintConcurrentLocks
-XX:+ExplicitGCInvokesConcurrent
这里的问题是,是什么触发了这一终身收藏,因为在老一代中,当它出现时,几乎有2gb的空闲空间。以下是在正常情况下终身收藏前的用法:
concurrent mark-sweep generation total 3145728K, used 2897098K
以下是在启动的最初几分钟内触发终身收藏之前的用法:
concurrent mark-sweep generation total 3145728K, used 1573655K
我的理解是,只有当老一代人快满的时候,才应该进行终身收藏;否则什么会触发它呢?CMS的一个关键概念是,它应该在空间用完之前开始收集,从而允许它同时运行。如果它一直等到你用完它就会触发一个序列停止世界收藏 因此,有两个阈值可以确定何时提前触发收集
-XX:CMSInitiatingOccupancyFraction=90 (by default)
-XX+UseCMSInitiatingOccupancyOnly
如果您不设置这些,那么何时开始使用“指标”将是一个好时机
我的理解是,只有当老一代人快满的时候,才应该进行终身收藏
这就是并行收集器所做的。感谢您的回复。你是说JVM不知道终身收集需要多长时间,所以它在第一次不必要地提前启动它?我明白不能等到它真的满了,但在我的情况下,它几乎是半满的。如果是这样的话,设置这两个标志是否会迫使JVM等到旧版本已满90%后再进行第一次终身收集?@Cameron这就是它应该做的,是的。我倾向于将eden的大小设置得非常大,例如24GB,这样就可以轻松调整使用空间;)你把你的伊甸园设置为24gb…所以你从来没有达到完整的GC,因为所有的东西都在young gen中?事实上,我从来没有达到过一个小的收集,因为我大部分时间都使用堆外空间,所以需要一天来填满伊甸园空间。这可能只适用于HFT;)我每天晚上运行一个完整的gc,这是一整天唯一的gc。