我在使用Concurrent Mark-Sweep收集器的应用程序的GC日志文件中看到以下症状:
4031.248: [CMS-concurrent-preclean-start]
4031.250: [CMS-concurrent-preclean: 0.002/0.002 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
4031.250: [CMS-concurrent-abortable-preclean-start]
CMS: abort preclean due to time 4036.346: [CMS-concurrent-abortable-preclean: 0.159/5.096 secs] [Times: user=0.00 sys=0.01, real=5.09 secs]
4036.346: [GC[YG occupancy: 55964 K (118016 K)]4036.347: [Rescan (parallel) , 0.0641200 secs]4036.411: [weak refs processing, 0.0001300 secs]4036.411: [class unloading, 0.0041590 secs]4036.415: [scrub symbol & string tables, 0.0053220 secs] [1 CMS-remark: 16015K(393216K)] 71979K(511232K), 0.0746640 secs] [Times: user=0.08 sys=0.00, real=0.08 secs]
预清洁过程不断中止。我已经尝试将CMSMaxAbortablePrecleanTime从默认值5调整为15秒,但这没有帮助。当前的JVM选项如下......
Djava.awt.headless=true
-Xms512m
-Xmx512m
-Xmn128m
-XX:MaxPermSize=128m
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:BiasedLockingStartupDelay=0
-XX:+DoEscapeAnalysis
-XX:+UseBiasedLocking
-XX:+EliminateLocks
-XX:+CMSParallelRemarkEnabled
-verbose:gc
-XX:+PrintGCTimeStamps
-XX:+PrintGCDetails
-XX:+PrintHeapAtGC
-Xloggc:gc.log
-XX:+CMSClassUnloadingEnabled
-XX:+CMSPermGenPrecleaningEnabled
-XX:CMSInitiatingOccupancyFraction=50
-XX:ReservedCodeCacheSize=64m
-Dnetworkaddress.cache.ttl=30
-Xss128k
似乎并发 - 流产 - 预清洁永远不会有机会跑。我通读https://blogs.oracle.com/jonthecollector/entry/did_you_know,其中有一个建议启用CMSScavengeBeforeRemark,但暂停的副作用似乎并不理想。有人可以提出任何建议吗?
另外,我想知道是否有人对CMS GC日志进行了很好的参考,特别是这一行:
[1 CMS-remark: 16015K(393216K)] 71979K(511232K), 0.0746640 secs]
不清楚这些数字所指的内存区域。 修改找到指向此http://www.sun.com/bigadmin/content/submitted/cms_gc_logs.jsp
的链接答案 0 :(得分:3)
[时间:用户= 0.00系统= 0.01,实际= 5.09秒]
我会尝试调查为什么CMS-concurrent-abortable-preclean-start
在5秒内没有同时获得用户和系统CPU时间。
我的建议是从“干净的”JVM CMS启动标志开始,如
-Djava.awt.headless=true
-Xms512m
-Xmx512m
-Xmn128m
-Xss128k
-XX:MaxPermSize=128m
-XX:+UseConcMarkSweepGC
-XX:+HeapDumpOnOutOfMemoryError
-Xloggc:gc.log
-XX:+PrintGCTimeStamps
-XX:+PrintGCDetails
-XX:+PrintHeapAtGC
然后检查问题是否重现并一次调整一个参数。
答案 1 :(得分:3)
正如某人已经提到的,第一步是增加CMSInitiatingOccupancyFraction。
作为第二步,我会使用标志-XX:-PrintTenuringDistribution
,并确保从年轻一代到旧年代都没有过早的提升。这将导致从年龄到年轻的参考,这可能导致更长的可流产的预清洁阶段。
如果存在这样的过早晋升,请尝试调整伊甸园和行星空间之间的比例。
答案 2 :(得分:2)
关于这种现象有一个很好的解释here:
引用:
所以当系统负载很轻时(这意味着没有 未成年人gc),预清理将永远超时,而gc将永远 失败。 cpu是浪费。
它不会失败。它将不那么平行(即效率较低,并且会 暂停时间较长,工作量较少。
总而言之:这似乎是正常的操作 - 线程只等待一次小的GC发生5秒钟,但是当没有发生时没有大问题:JVM选择不同的(效率较低)继续使用GC的策略。