【问题标题】:Why does G1GC shrink the young generation before starting mixed collections?为什么 G1GC 在开始混合收集之前会收缩年轻代?
【发布时间】:2016-07-20 14:46:34
【问题描述】:

当 G1 决定需要开始混合收集时,它会积极地将我们的 Eden 空间从 10g 缩小到大约 1g。

{Heap before GC invocations=294 (full 0):
 garbage-first heap   total 20480000K, used 18304860K [0x00000002de000000, 0x00000002de804e20, 0x00000007c0000000)
  region size 8192K, 1363 young (11165696K), 11 survivors (90112K)
 Metaspace       used 37327K, capacity 37826K, committed 38096K, reserved 1083392K
  class space    used 3935K, capacity 4081K, committed 4096K, reserved 1048576K
2016-03-31T20:57:31.002+0000: 7196.427: [GC pause (G1 Evacuation Pause) (young)
Desired survivor size 717225984 bytes, new threshold 1 (max 1)
- age   1:   41346816 bytes,   41346816 total
 7196.427: [G1Ergonomics (CSet Construction) start choosing CSet, _pending_cards: 144693, predicted base time: 48.88 ms, remaining time: 951.12 ms, target pause time: 1000.00 ms]
 7196.427: [G1Ergonomics (CSet Construction) add young regions to CSet, eden: 1352 regions, survivors: 11 regions, predicted young region time: 20.72 ms]
 7196.427: [G1Ergonomics (CSet Construction) finish choosing CSet, eden: 1352 regions, survivors: 11 regions, old: 0 regions, predicted pause time: 69.60 ms, target pause time: 1000.00 ms]
 7196.494: [G1Ergonomics (Mixed GCs) start mixed GCs, reason: candidate old regions available, candidate old regions: 789 regions, reclaimable: 4703761904 bytes (22.43 %), threshold: 5.00 %]
, 0.0673540 secs]
   [Parallel Time: 60.1 ms, GC Workers: 18]
      [GC Worker Start (ms): Min: 7196427.8, Avg: 7196428.1, Max: 7196428.2, Diff: 0.4]
      [Ext Root Scanning (ms): Min: 7.3, Avg: 7.5, Max: 7.7, Diff: 0.4, Sum: 134.2]
      [Update RS (ms): Min: 28.2, Avg: 28.8, Max: 29.9, Diff: 1.7, Sum: 518.4]
         [Processed Buffers: Min: 41, Avg: 57.7, Max: 80, Diff: 39, Sum: 1039]
      [Scan RS (ms): Min: 0.1, Avg: 0.2, Max: 0.5, Diff: 0.4, Sum: 3.7]
      [Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
      [Object Copy (ms): Min: 22.1, Avg: 23.1, Max: 23.4, Diff: 1.3, Sum: 416.2]
      [Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
         [Termination Attempts: Min: 1, Avg: 1.0, Max: 1, Diff: 0, Sum: 18]
      [GC Worker Other (ms): Min: 0.0, Avg: 0.1, Max: 0.2, Diff: 0.2, Sum: 2.5]
      [GC Worker Total (ms): Min: 59.5, Avg: 59.7, Max: 60.0, Diff: 0.5, Sum: 1075.1]
      [GC Worker End (ms): Min: 7196487.7, Avg: 7196487.8, Max: 7196487.9, Diff: 0.2]
   [Code Root Fixup: 0.2 ms]
   [Code Root Purge: 0.0 ms]
   [Clear CT: 1.9 ms]
   [Other: 5.2 ms]
      [Choose CSet: 0.0 ms]
      [Ref Proc: 0.5 ms]
      [Ref Enq: 0.0 ms]
      [Redirty Cards: 0.5 ms]
      [Humongous Register: 0.2 ms]
      [Humongous Reclaim: 0.1 ms]
      [Free CSet: 2.3 ms]
   [Eden: 10.6G(10.6G)->0.0B(848.0M) Survivors: 88.0M->152.0M Heap: 17.5G(19.5G)->7128.3M(19.5G)]
Heap after GC invocations=295 (full 0):
 garbage-first heap   total 20480000K, used 7299344K [0x00000002de000000, 0x00000002de804e20, 0x00000007c0000000)
  region size 8192K, 19 young (155648K), 19 survivors (155648K)
 Metaspace       used 37327K, capacity 37826K, committed 38096K, reserved 1083392K
  class space    used 3935K, capacity 4081K, committed 4096K, reserved 1048576K
}
 [Times: user=1.09 sys=0.00, real=0.07 secs]
2016-03-31T20:57:31.070+0000: 7196.495: Total time for which application threads were stopped: 0.0699324 seconds, Stopping threads took: 0.0003462 seconds

这是在使用 10-11g 的 Eden 运行 60 次或更多集合之后。

以下是我们运行时使用的适当 JVM GC 参数

-Xms20000m -Xmx20000m
-XX:+UseG1GC 
-XX:G1RSetUpdatingPauseTimePercent=5 
-XX:MaxGCPauseMillis=1000 
-XX:GCTimeRatio=99 
-XX:InitiatingHeapOccupancyPercent=35 
-XX:MaxTenuringThreshold=1 
-XX:G1ConcRefinementThreads=6 
-XX:ConcGCThreads=18 
-XX:ParallelGCThreads=18

-XX:+PrintGCDetails"
-XX:+PrintGCDateStamps"
-XX:+PrintHeapAtGC"
-XX:+PrintTenuringDistribution"
-XX:+PrintGCApplicationStoppedTime"
-XX:+PrintPromotionFailure"
-XX:+PrintAdaptiveSizePolicy"

根据page 55 of this presentation,它需要调整 Eden 的大小,以便 max pause 目标占整个堆,而不仅仅是新生代。收藏家为何如此咄咄逼人?

对于 10g 的堆大小,平均年轻代暂停时间在 50-150 毫秒之间。如果演示文稿是正确的(我还没有找到其他任何东西来支持该陈述),我预计会缩小一半(20g 堆),而不是 10 倍。

【问题讨论】:

  • 我刚刚通读了那个演示文稿(确实非常好),但我在幻灯片 55 上没有看到您在帖子中提到的相同内容。而且,它显示了一个伊甸园从 12.5gb 减少到
  • 并且,也许考虑添加 print-adaptive-size-policy 标志。
  • @EngineerDollery PrintAdaptiveSizePolicy 参数已启用(添加到问题中)。在第 3 期的演示文稿中,它指出“必须考虑老区域,不仅是年轻区域,目前 G1 缩小了年轻一代”。理想情况下,我根本不希望这一代人萎缩。我们将暂停目标设置为 1000 毫秒,并且收集速度比这快得多。必须收集两次垃圾(已标记)不应该超过两倍的时间。
  • 您对 G1 施加了很多限制。你确定每个参数现在都是合理的吗?如果新一代的缩小确实是问题所在,为什么不为它设置一个最小尺寸呢?
  • @the8472 我们可以在聊天中进行讨论(虽然你必须创建它,但我没有足够的声望)。

标签: java garbage-collection heap-memory g1gc


【解决方案1】:

您可以在第 56 张幻灯片中找到问题的答案

年轻一代缩小了 20 倍

所以缩小 10 倍的工厂也就不足为奇了。

来自infoQ Monica Beckwith 关于 G1GC 调优技巧的文章:

完全可以通过让nursery/young gen缩小到默认最小值(Java堆总量的5%)来避免Full GC

由于您没有明确设置年轻一代的大小,默认值为

-XX:G1NewSizePercent=5

设置堆的百分比以用作年轻代大小的最小值。

所以要尊重你的暂停时间目标

-XX:MaxGCPauseMillis=1000 

young gen 最多可以缩小总堆的 5%。

我在 Google 小组中找到了一篇关于 G1GC 的好文章 https://groups.google.com/a/jclarity.com/forum/#!msg/friends/hsZiz6HTm9M/klrRjBclCwAJ

如果 G1 预测的暂停时间目标大于目标暂停时间目标,则收缩年轻代,但不超过当前 Java 堆大小的 G1NewSizePercent,(不是最大大小)。同样,整体 Java 堆将根据计算出的 GC 时间比率值与 GCTimeRatio 值的关系而增长(或缩小)。

注意:G1NewSizePercentG1MaxNewSizePercent 不得与 NewSizeMaxNewSize 混淆。

G1NewSizePercentG1MaxNewSizePercent 分别设置了 G1 可以调整多少年轻代的大小的下限和上限。

另一方面,您已经配置了许多可能不必要的参数,因为如果大多数默认参数已设置为默认值,G1GC 可以正常工作。有关详细信息,请参阅此 SE 问题。

Java 7 (JDK 7) garbage collection and documentation on G1

总结根据暂停时间目标,年轻一代会缩小。如果你真的担心young gen 缩水到低价值,配置-XX:G1NewSizePercent。但是只要遇到-XX:MaxGCPauseMillis我就不推荐了

编辑:

来自 G1GC ergonomics 页面,

当垃圾收集器试图满足竞争目标时,堆的大小通常会发生波动。 即使应用程序已达到稳定状态也是如此。实现吞吐量目标(可能需要更大的堆)的压力与最大暂停时间和最小占用空间(两者都可能需要小堆)的目标竞争。

【讨论】:

  • 所以你的回答是因为它可以?这不满足我,你目前没有任何文档支持它。正如我从打印的 GC 详细信息中显示的那样,暂停时间已经在最大暂停时间目标内。没有理由调整这么多。调整这么多会导致应用程序更加紧张。目前,这个应用可以在 2-3 秒内产生 10g 的垃圾。使用 800m 的新堆,JVM 将每隔几百毫秒进行一次 gc'ing。这会对吞吐量产生负面影响。
  • 来自 oracle 文档页面:G1 GC 有一个暂停时间目标,它试图满足(软实时)。在年轻收集期间,G1 GC 调整其年轻代(伊甸园和幸存者大小)以满足软实时目标。在混合回收期间,G1 GC 会根据混合垃圾回收的目标数量、堆中每个区域中活动对象的百分比以及总体可接受的堆浪费百分比来调整回收的旧区域的数量。
  • 本文和infoq文章提供证明。
  • 我的观点是 JVM 应该在不调整年轻代大小的情况下达到暂停时间目标。这太激进了,我想知道为什么。你的回答没有解决这个问题,aggressiveness
  • 年轻/混合 gc 在停止世界处理器的情况下运行。将其保持在较低水平有助于实现暂停时间目标。
【解决方案2】:

使用 MaxTenuringThreshold=1 时,您告诉 GC 在仅存活 1 个 GC 周期后将对象提升到老年代。在大多数应用程序中,这将导致许多过早的促销活动。如果过早提升太多对象,你的老代会迅速增长,因此它必须缩小年轻代为老代腾出空间

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-02
    • 1970-01-01
    • 1970-01-01
    • 2017-10-01
    • 2015-07-30
    • 2014-12-04
    • 1970-01-01
    相关资源
    最近更新 更多