当InitiatingHeapOccupancyPercent实现时,为什么G1不会启动标记周期?

时间:2016-04-20 22:12:11

标签: java garbage-collection g1gc

根据documentationXX:InitiatingHeapOccupancyPercent

  

设置触发标记周期的Java堆占用率阈值。   默认占用率是整个Java堆的45%。

在我目前的环境中,这种情况不会发生。

我的G1垃圾收集配置如下

-Xms25000m
-Xmx25000m
-XX:+UseG1GC
-XX:MaxGCPauseMillis=1000
-XX:GCTimeRatio=99
-XX:InitiatingHeapOccupancyPercent=70
-XX:MaxTenuringThreshold=8
-XX:+UnlockExperimentalVMOptions
-XX:G1MixedGCCountTarget=16
-XX:G1OldCSetRegionThresholdPercent=3
-XX:G1NewSizePercent=30
-XX:G1RSetUpdatingPauseTimePercent=5

当一个25g的堆和一个XX:InitiatingHeapOccupancyPercent的70%时,你会期望在18g被占用时开始一个标记周期。我拖尾垃圾收集日志并没有发生。

这是一个摘录:

{Heap before GC invocations=592 (full 0):
 garbage-first heap   total 25600000K, used 22802164K [0x00000001a5800000, 0x00000001a60061a8, 0x00000007c0000000)
  region size 8192K, 1526 young (12500992K), 25 survivors (204800K)
 Metaspace       used 37386K, capacity 37948K, committed 38144K, reserved 1083392K
  class space    used 3948K, capacity 4080K, committed 4096K, reserved 1048576K
2016-04-20T22:06:38.272+0000: 4213.406: [GC pause (GCLocker Initiated GC) (young)
Desired survivor size 801112064 bytes, new threshold 8 (max 8)
- age   1:   98537800 bytes,   98537800 total
- age   2:    7053912 bytes,  105591712 total
- age   3:    6556320 bytes,  112148032 total
- age   4:    8836064 bytes,  120984096 total
- age   5:    5725448 bytes,  126709544 total
- age   6:    6702728 bytes,  133412272 total
- age   7:    3831920 bytes,  137244192 total
- age   8:    4166336 bytes,  141410528 total
 4213.406: [G1Ergonomics (CSet Construction) start choosing CSet, _pending_cards: 184844, predicted base time: 44.67 ms, remaining time: 955.33 ms, target pause time: 1000.00 ms]
 4213.406: [G1Ergonomics (CSet Construction) add young regions to CSet, eden: 1501 regions, survivors: 25 regions, predicted young region time: 21.21 ms]
 4213.406: [G1Ergonomics (CSet Construction) finish choosing CSet, eden: 1501 regions, survivors: 25 regions, old: 0 regions, predicted pause time: 65.88 ms, target pause time: 1000.00 ms]
 4213.475: [G1Ergonomics (Heap Sizing) attempt heap expansion, reason: recent GC overhead higher than threshold after GC, recent GC overhead: 1.40 %, threshold: 1.00 %, uncommitted: 0 bytes, calculated expansion amount: 0 bytes (20.00 %)]
, 0.0687163 secs]
   [Parallel Time: 61.7 ms, GC Workers: 28]
      [GC Worker Start (ms): Min: 4213406.9, Avg: 4213407.1, Max: 4213407.3, Diff: 0.4]
      [Ext Root Scanning (ms): Min: 6.0, Avg: 6.2, Max: 6.4, Diff: 0.4, Sum: 173.1]
      [Update RS (ms): Min: 33.5, Avg: 34.0, Max: 34.6, Diff: 1.1, Sum: 951.9]
         [Processed Buffers: Min: 27, Avg: 36.6, Max: 48, Diff: 21, Sum: 1024]
      [Scan RS (ms): Min: 0.1, Avg: 0.2, Max: 0.5, Diff: 0.4, Sum: 6.3]
      [Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
      [Object Copy (ms): Min: 20.1, Avg: 20.6, Max: 20.8, Diff: 0.7, Sum: 577.5]
      [Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.7]
         [Termination Attempts: Min: 1, Avg: 13.2, Max: 19, Diff: 18, Sum: 371]
      [GC Worker Other (ms): Min: 0.0, Avg: 0.2, Max: 0.4, Diff: 0.3, Sum: 4.7]
      [GC Worker Total (ms): Min: 60.9, Avg: 61.2, Max: 61.6, Diff: 0.6, Sum: 1714.2]
      [GC Worker End (ms): Min: 4213468.2, Avg: 4213468.3, Max: 4213468.5, Diff: 0.3]
   [Code Root Fixup: 0.4 ms]
   [Code Root Purge: 0.0 ms]
   [Clear CT: 1.2 ms]
   [Other: 5.4 ms]
      [Choose CSet: 0.0 ms]
      [Ref Proc: 0.5 ms]
      [Ref Enq: 0.0 ms]
      [Redirty Cards: 0.8 ms]
      [Humongous Register: 0.2 ms]
      [Humongous Reclaim: 0.0 ms]
      [Free CSet: 2.4 ms]
   [Eden: 11.7G(11.7G)->0.0B(11.7G) Survivors: 200.0M->200.0M Heap: 21.7G(24.4G)->10.0G(24.4G)]
Heap after GC invocations=593 (full 0):
 garbage-first heap   total 25600000K, used 10516798K [0x00000001a5800000, 0x00000001a60061a8, 0x00000007c0000000)
  region size 8192K, 25 young (204800K), 25 survivors (204800K)
 Metaspace       used 37386K, capacity 37948K, committed 38144K, reserved 1083392K
  class space    used 3948K, capacity 4080K, committed 4096K, reserved 1048576K
}
 [Times: user=1.70 sys=0.01, real=0.07 secs] 
2016-04-20T22:06:38.342+0000: 4213.475: Total time for which application threads were stopped: 0.0701353 seconds, Stopping threads took: 0.0001600 seconds

我会引起你的注意

{Heap before GC invocations=592 (full 0):
   garbage-first heap   total 25600000K, used 22802164K [0x00000001a5800000, 0x00000001a60061a8, 0x00000007c0000000)
[...]
[Eden: 11.7G(11.7G)->0.0B(11.7G) Survivors: 200.0M->200.0M Heap: 21.7G(24.4G)->10.0G(24.4G)]

在此集合之前,超过70%的堆已被占用。为什么这不会触发标记周期?

该应用程序继续进行年轻代收集,填补旧区域,最终导致分配失败和冗长的全GC。

InitiatingHeapOccupancyPercent减少到55没有明显的效果。

在20岁时,它确实开始进行混合收集,但只有当约80%的堆被占用时才会开始。

1 个答案:

答案 0 :(得分:6)

JDK-6976060表明在年轻的GC结束时需要计算标记周期。根据它是否使用年轻GC之前或之后的占用统计数据,这可能意味着也可能不意味着伊甸园空间总是被视为占用IHOP计算的0%。拥有45%的伊甸园大小意味着永远不会达到70%的占用率,最大可能占用率将达到55%,此时堆将完全填满,对于混合收集来说为时已晚。

但我怀疑这是否真的如此,因为面对动态的年轻一代规模,这会使文档误导,IHOP调整更加困难。使用人工测试用例和手动调整代数来验证这一点应该相当容易。

如果那不是问题,那么GC pause (GCLocker Initiated GC) (young)可能会指向bug 8140597,这已在jdk9b94中修复。

更新:Bug 8151176中的描述确实表明,为了IHO百分比计算,它计算oldgen占用率/总堆大小。这意味着年轻一代的入住率被完全忽略,这反过来又意味着年轻人的分数> IHOP然后它永远不会启动并发周期。

  

原因是如果旧的占用率超过当前堆容量的固定百分比,则静态IHOP启动。如果用户或人体工程学决定旧的gen不能大于触发并发标记的堆容量的那一部分,则标记将永远不会开始。

目前可用的解决方案是

  • 约束年轻分数< IHOP
  • 减少IHOP以考虑最小可能的旧基因部分
  • 让JVM动态调整IHOP