简短回答:
CMS在没有必要的情况下花费太多时间扫描近10GB的Young Gen。您可以通过添加以下选项来防止CMS收集器不必要地运行:
‑XX:+UseCMSInitiatingOccupancyOnly ‑XX:CMSInitiatingOccupancyFraction=<K>
其中K是占用的Old Gen空间的任意分数。
详细回答:
参考Oracle CMS文档:
CMS收集器在并发收集周期中暂停应用程序两次。第一次暂停是为了标记从根(例如,应用程序线程堆栈和寄存器、静态对象等)和堆的其他位置(例如,young generation)直接可达的对象。这个第一次暂停被称为初始标记暂停。第二个暂停发生在并发跟踪阶段的结束,找到了由于应用程序线程在CMS收集器完成跟踪该对象后更新该对象的引用而被并发跟踪遗漏的对象。这个第二次暂停被称为重新标记暂停。
CMS在两个stop-the-world暂停期间每次都会扫描Young Gen进行标记。查看日志的前三行,您可以看到初始标记需要5秒钟,然后是ParNew,之后又需要0.25秒。重新标记也有类似的时间减少。
<190>1 2015-12-18T08:44:54.194216+00:00 host app web.1 - [GC[YG occupancy: 489826 K (9437184 K)][Rescan (parallel) , 0.2520950 secs][weak refs processing, 0.0000180 secs][scrub string table, 0.0008190 secs] [1 CMS-remark: 64504K(107240K)] 554330K(9544424K), 0.2530410 secs] [Times: user=1.95 sys=0.02, real=0.25 secs]
<190>1 2015-12-18T08:44:49.937257+00:00 host app web.1 - [GC[ParNew: 8418004K->93508K(9437184K), 0.0488580 secs] 8482343K->158013K(9544424K), 0.0489980 secs] [Times: user=0.33 sys=0.00, real=0.05 secs]
<190>1 2015-12-18T08:44:48.651086+00:00 host app web.1 - [GC [1 CMS-initial-mark: 64339K(107240K)] 7800216K(9544424K), 5.0756660 secs] [Times: user=5.08 sys=0.00, real=5.08 secs]
每个CMS循环后,您的旧代空间几乎不会被减少,因此这种开销肯定不值得。降低CMS循环的频率是一种可能的解决方案。