当你说 CMS 收集器跟不上你的对象提升率时,这意味着你应该在 GC 日志中看到“并发模式失败”。当 CMS 收集器“输掉比赛”并且您在完成之前内存不足时,您会得到这些。
2014-02-27T01:09:52.408-0600: 847.004: [GC 847.005: [ParNew
(promotion failed)
Desired survivor size 78512128 bytes, new threshold 2 (max 15)
- age 1: 60284680 bytes, 60284680 total
- age 2: 32342648 bytes, 92627328 total
: 1380096K->1380096K(1380096K), 0.7375510 secs]847.743:
[CMS2014-02-27T01:09:54.133-0600: 848.729: [CMS-concurrent-s
weep: 5.467/6.765 secs] [Times: user=21.59 sys=0.73, real=6.76
secs]
(concurrent mode failure): 2363866K->1763900K(4409856K),
10.6658960 secs] 3697627K->1763900K(5789952K), [CMS Perm :
118666K->117980K(125596K)], 11.4061610 secs]
[Times: user=11.34 sys=0.02, real=11.57 secs]
默认情况下,CMS 收集器将在老年代的 92% 占用率时触发。从老年代使用图表中的内存增长率来看,您每 5 分钟增长约 500 MB。6GB 的 92% 为您提供了大约 500 MB 的动态余量,这意味着 CMS 必须在 5 分钟内赢得比赛,它会的。除非...
...除了我们在图中看到的流畅的交通状况之外,您还有一些幕后发生的事情。例如,您是否有任何后台进程可以刷新内存中的数据结构(如缓存)?这些类型的活动会突然产生大量新的、长期存在的对象,这些对象需要升级到老一代。它会使您的平滑图突然变得垂直,并且可以快速耗尽可用内存。CMS 收集器擅长处理平稳、稳定的流量,但它很容易受到快速突发活动的影响。它擅长响应你的垃圾生成率的逐渐变化,但它无法预测“突发”行为,我见过很多这样的案例,导致它输掉比赛。
除了完全避免产生新对象突然爆发的后台进程之外,您还可以通过将 CMSInitiatingOccupancyFraction 参数降低到 60-80 而不是默认值 92% 来让 CMS 收集器领先一步。
http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html#cms.starting_a_cycle
另外,也要留意你的 PermGen 空间。与并行吞吐量收集器不同,CMS 收集器默认不收集 PermGen,因此如果它填满,您最终会得到一个 stop-the-world 的完整 GC。此参数使 CMS 收集器也收集 PermGen 空间:CMSClassUnloadingEnabled。
除此之外,我建议打开 GC 日志记录和设置: -XX:+PrintGCDetails 打印有关每个次要和主要垃圾收集的详细信息
这是一个很棒的参数,可以让您在启动时查看每个 JVM 设置:-XX:+PrintFlagsFinal 在启动时打印所有 JVM 配置选项的值