【问题标题】:Java CMS GC BehavioursJava CMS GC 行为
【发布时间】:2011-07-16 10:01:29
【问题描述】:

我有一个导致产生大量垃圾的应用程序。第一个(也是几乎一个)标准是低 GC 暂停时间。我使用 visualgc 工具(和 gc 日志)尝试不同的 GC 参数。最佳参数如下。

-XX:+UseConcMarkSweepGC

-Xmx1172M

-Xms600M

-XX:+UseParNewGC

-XX:NewSize=150M

我的应用程序在带有 Java 1.6.0_21 的 SunOS 10 上运行。硬件为 2 x CPU 四核(uname -X 结果为 numCPU = 8)。

问题是

观察 GC 行为,在伊甸园空间创建新对象,直到伊甸园满。当 eden space full GC 运行时,清除垃圾,如果对象不是到 Old-gen 的死副本(我丢弃 'from' 和 'to' 空间),同样 Old-Gen 已满,GC 在 CMS-concurrent 阶段运行并清除 Old -gen 空间。 CMS 的某些部分是 Stop-the-world(暂停时间)。这是一个循环。

  1. 上面的场景是真的吗?
  2. GC clean old-gen space后,没有足够的空间expand old-gen space(XMS和XMS值不同)?
  3. Full GC 操作何时开始?如何决定?
  4. CMS 并发阶段持续时间取决于 Eden 空间大小,实际上我的预期是,Eden 空间不会影响 CMS 并发阶段持续时间。在 CMS 并发阶段,与伊甸园空间相关的 GC 发生了什么?
  5. 还有什么建议可以减少暂停时间?的确,对我来说最有价值的答案:)

谢谢

【问题讨论】:

    标签: java garbage-collection


    【解决方案1】:

    在使用 CMS 时,您不能只忽略幸存者空间。 CMS 不是一个压缩收集器,这意味着如果您(或 JVM)错误地设置了使用期限阈值,那么您将缓慢地将对象流血到永久期限中,这将增加永久期限碎片的速率,这将提前强制 CMS 的时间,因为它没有足够的连续可用空间来处理从幸存者空间到终身的提升,这将强制一个完整的 gc 周期而没有提前警告,因此它是 1 STW 暂停中的全部内容。这需要多长时间取决于您的堆大小,但很可能有一件事,它会比普通的伊甸园集合长几个数量级。

    这里还有一些需要注意的地方;

    1. STW 暂停不仅来自 CMS,它们也来自年轻一代收集器
    2. CMS 有 2 个 STW 阶段(标记和备注)和 3-4 个并发阶段,第一个 STW 阶段(标记)是严格的单线程,可能会导致问题(关于此here 的示例讨论)
    3. 您可以控制处理并发阶段的线程数
    4. 您需要了解对象的寿命,这可能意味着使用 -XX:+PrintTenuringDistribution 或者您可以像以前一样使用 visualgc 观看它
    5. 然后您可以使用-XX:SurvivorRatio 调整它以控制幸存者空间相对于伊甸园的大小,并使用-XX:MaxTenuringThreshold 来控制一个对象在其被永久保存之前能够在年轻集合中存活的频率
    6. -XX:CMSInitiatingOccupancyFraction 可用于指导 CMS 在开始 CMS 阶段之前它需要多满(如果弄错了,你会严重停顿)

    最终,您需要了解暂停的收集器、暂停的频率、暂停的时间以及是否有任何异常原因导致暂停。然后,您需要将其与每一代的大小进行比较,看看您是否可以调整参数以最小化暂停的数量(和/或持续时间)。

    请记住,由于需要长时间运行测试以查看它是否会随着时间的推移而恶化,因此这可能会造成时间损失。此外,如果没有可重复的自动化工作负载,几乎不可能得出任何确定的结论来确定您是否确实改进了一些东西。

    内部摘要信息的一个很好的来源是Jon Masamitsu's blog。另一个很好的介绍是GC Tuning in the HotSpot Java VM

    【讨论】:

    • 20 小时后,gc 记录了大约 5 次 full gc 运行,我猜想一些线索为什么运行 Full GC 是“升级失败”和“并发模式失败”。在google上搜索这些原因。很快,为“升级失败”增加老年代大小,并为“并发模式失败”设置最小值 XX:CMSInitiatingOccupancyFraction。我将尝试设置 XX:CMSInitiatingOccupancyFraction 小值(如 30 或 60)并增加堆。我将分享测试结果。
    • 提升失败通常是我提到的碎片问题,它会强制执行非并发的完整 gc。您需要检查您的任期阈值并适当调整它们的大小。将初始占用率设置为较低的值(默认值为 70 iirc)只会意味着更频繁的完整 gcs 不会做太多,这是不好的。你甚至有很多可以长期生活的东西吗?你可能会发现一个巨大的伊甸园和一个小小的终身职位是一个不错的选择。
    • 低初始占用值是更频繁的 CMS 但没问题。最大问题 STW 时 2-3 秒。吞吐量或 0.0x 秒 STW 对我来说不是问题。我尝试过大伊甸园大小,但 STW 持续时间增加了 :( 如何在并发阶段设置线程数?
    • 你能打印那个暂停的 gc 日志输出吗?看看它花时间在做什么会很有趣。使用ParallelCMSThreads设置线程数,解释here
    【解决方案2】:

    最小化 GC 影响的最佳方法是最小化您创建的对象对象的数量。这并不总是容易做到或总体上是最佳解决方案,但它会最大限度地减少 GC 暂停。

    如果您不能生产更少的对象,请尝试使它们的寿命足够短,并使伊甸园空间足够大,以使它们不会离开伊甸园空间。 (或者让寿命很长的可以重复使用)

    1. 这里需要担心三个空格,eden ->survivor ->tenured http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html

    2. 1234563 /p>
    3. 完整的 GC 会在永久空间已满或幸存者空间用尽(例如从伊甸园空间复制的对象过多)或 CMS 设备现在是一个很好的 tile 来尝试执行并发清理。

    4. CMS 只清理永久空间。

    5. 查看我之前的回答。

    【讨论】:

    • 我同意你关于增加伊甸园空间的决定。我已经尝试了不同的 newSize 参数,并从 gc 日志中检查暂停时间,该行包括“重新扫描”。较少的 newSize 值会导致较少的暂停时间。 3 个不同的 newSize 值与我的推断平行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-03
    • 1970-01-01
    • 1970-01-01
    • 2012-11-18
    • 2018-12-17
    相关资源
    最近更新 更多