2

在一个中等繁忙的生产服务器(50 个应用线程,30% 的 CPU 利用率)上,我们看到 CMS 收集器无法跟上提升到老一代的对象的速度。

我最初的想法是这些对象显然仍然被引用,因此不符合收集条件 - 但是当 Old Gen 填充并提示串行收集时,6 GiB 中的 5.5 GiB 被回收。

Eden 空间的大小为 3 GiB,大约需要 20-30 秒才能填充足够的空间以提示年轻集合。幸存者空间使用量在 800 - 1250 MiB 之间波动,最大为 1.5 GiB(每个)。

由于旧代中的对象符合收集条件,并且服务器具有大量(明显)资源,我不明白为什么 CMS 收集器没有保持在旧代大小之上:

视觉虚拟机

什么可能导致这种情况,有什么解决方案吗?

我知道占用率,但我不明白CMSIncrementalSafetyFactor- 我已经阅读了一些 Oracle 文档,但我不知道“在计算占空比时添加 [ing] 保守主义”实际上意味着什么。 .?

备择方案

切换到并行/吞吐量收集器会产生非常低的 GC 开销(1.8%),但偶尔会留下(每天 50 次)长时间的停顿——每次完整 GC 大约 20 秒。即使进行了一些调整,这也不太可能达到我们的最大暂停目标。

在理想情况下,我们可以尝试使用 G1 收集器,但由于各种原因,我们只能使用 Java 6 JVM。

4

1 回答 1

1

当你说 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 配置选项的值

于 2015-08-18T03:28:45.120 回答