【问题标题】:CMS collector not keeping pace with Old GenCMS 收集器跟不上老一代
【发布时间】:2016-03-25 10:43:05
【问题描述】:

在一个中等繁忙的生产服务器(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 文档,但我不知道在计算工作周期”实际上意味着..?

替代品

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

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

【问题讨论】:

  • 查看 GC 日志事件的输出可以让您更深入地了解。
  • @MarkoTopolnik 有什么我应该寻找的特定事件吗?我查看了日志,但没有任何异常(在我看来)。
  • 我希望所有 CMS 相变事件的时间和实际收集的数量应该比现在提出的问题更清晰。

标签: java garbage-collection concurrent-mark-sweep


【解决方案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配置选项的值

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-24
    • 1970-01-01
    • 2017-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多