G1会动态调整年轻代和老年代空间大小,为了达到接近预期的暂停时间;G1提供了两种GC模式,Young GC和Mixed GC,两种都是Stop The World(STW)的。
当达到IHOP阈值-XX:InitiatingHeapOccupancyPercent(老年代占整堆比,默认45%)时,便会触发并发标记周期。
整个并发标记周期将由初始标记(Initial Mark)、根分区扫描(Root Region Scanning)、并发标记(Concurrent Marking)、重新标记(Remark)、清除(Cleanup)几个阶段组成。
其中,初始标记(随年轻代收集一起活动)、重新标记、清除是STW的,
初始标记(Initial Mark)
2021-11-05T14:39:40.189+0800: 16373.190: [GC pause (G1 Evacuation Pause) (young) (initial-mark), 0.0579957 secs]
[Parallel Time: 44.5 ms, GC Workers: 8]
[GC Worker Start (ms): Min: 16373191.1, Avg: 16373191.3, Max: 16373191.9, Diff: 0.7]
[Ext Root Scanning (ms): Min: 0.3, Avg: 1.0, Max: 2.1, Diff: 1.8, Sum: 8.1]
[Update RS (ms): Min: 6.6, Avg: 7.4, Max: 8.1, Diff: 1.5, Sum: 59.5]
[Processed Buffers: Min: 12, Avg: 15.9, Max: 23, Diff: 11, Sum: 127]
[Scan RS (ms): Min: 15.7, Avg: 16.1, Max: 16.4, Diff: 0.7, Sum: 128.6]
[Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Object Copy (ms): Min: 18.7, Avg: 18.9, Max: 19.0, Diff: 0.3, Sum: 151.0]
[Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Termination Attempts: Min: 1, Avg: 1.5, Max: 2, Diff: 1, Sum: 12]
[GC Worker Other (ms): Min: 0.0, Avg: 0.1, Max: 0.3, Diff: 0.3, Sum: 1.1]
[GC Worker Total (ms): Min: 43.1, Avg: 43.5, Max: 43.8, Diff: 0.7, Sum: 348.4]
[GC Worker End (ms): Min: 16373234.8, Avg: 16373234.9, Max: 16373235.0, Diff: 0.2]
[Code Root Fixup: 0.1 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 1.4 ms]
[Other: 12.0 ms]
[Choose CSet: 0.0 ms]
[Ref Proc: 7.5 ms]
[Ref Enq: 0.4 ms]
[Redirty Cards: 0.6 ms]
[Humongous Register: 0.1 ms]
[Humongous Reclaim: 0.0 ms]
[Free CSet: 2.3 ms]
[Eden: 378.0M(378.0M)->0.0B(545.0M) Survivors: 20.0M->22.0M Heap: 625.4M(2048.0M)->250.1M(2048.0M)]
[Times: user=0.36 sys=0.01, real=0.06 secs]
根分区扫描(Root Region Scanning)
2021-11-05T14:39:40.247+0800: 16373.249: [GC concurrent-root-region-scan-start]
2021-11-05T14:39:40.308+0800: 16373.310: [GC concurrent-root-region-scan-end, 0.0610685 secs]
并发标记(Concurrent Marking)
2021-11-05T14:39:40.308+0800: 16373.310: [GC concurrent-mark-start]
2021-11-05T14:39:40.533+0800: 16373.535: [GC concurrent-mark-end, 0.2253183 secs]
重新标记(Remark)
2021-11-05T14:39:40.534+0800: 16373.536: [GC remark 2021-11-05T14:39:40.534+0800: 16373.536: [Finalize Marking, 0.0005696 secs] 2021-11-05T14:39:40.535+0800: 16373.536: [GC ref-proc, 0.0045710 secs] 2021-11-05T14:39:40.539+0800: 16373.541: [Unloading, 0.0077477 secs], 0.0146888 secs]
清除(Cleanup)
2021-11-05T14:39:40.549+0800: 16373.551: [GC cleanup 253M->252M(2048M), 0.0061561 secs]
[Times: user=0.02 sys=0.01, real=0.00 secs]
2021-11-05T14:39:40.556+0800: 16373.558: [GC concurrent-cleanup-start]
2021-11-05T14:39:40.556+0800: 16373.558: [GC concurrent-cleanup-end, 0.0000344 secs]
下面是整个mixed gc日志:看到初始标记(Initial Mark)、根分区扫描(Root Region Scanning)、并发标记(Concurrent Marking)、重新标记(Remark)、清除(Cleanup) 总耗时在0.4秒; 而一个yong gc耗时是在0.07秒;
条件:-Xmx2048m -Xms2048m -XX:G1HeapWastePercent=10 -XX:InitiatingHeapOccupancyPercent=20
结果:
持续发送一天的数据, 观察opentsdb的old gc分区使用内存和整个堆的占比会一直在10%-30%之间徘徊, 不会一直增长,有效的回收
mixed gc
2021-11-05T15:14:48.654+0800: 18481.656: [GC pause (G1 Evacuation Pause) (young) (initial-mark), 0.0719531 secs]
[Parallel Time: 55.8 ms, GC Workers: 8]
[GC Worker Start (ms): Min: 18481656.6, Avg: 18481656.9, Max: 18481657.5, Diff: 1.0]
[Ext Root Scanning (ms): Min: 0.7, Avg: 1.6, Max: 4.0, Diff: 3.2, Sum: 12.6]
[Update RS (ms): Min: 7.5, Avg: 9.4, Max: 10.4, Diff: 2.9, Sum: 74.9]
[Processed Buffers: Min: 10, Avg: 13.0, Max: 25, Diff: 15, Sum: 104]
[Scan RS (ms): Min: 18.9, Avg: 19.2, Max: 19.5, Diff: 0.6, Sum: 154.0]
[Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Object Copy (ms): Min: 24.6, Avg: 24.8, Max: 25.0, Diff: 0.5, Sum: 198.1]
[Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Termination Attempts: Min: 1, Avg: 5.8, Max: 9, Diff: 8, Sum: 46]
[GC Worker Other (ms): Min: 0.0, Avg: 0.1, Max: 0.2, Diff: 0.1, Sum: 0.8]
[GC Worker Total (ms): Min: 54.5, Avg: 55.1, Max: 55.4, Diff: 0.9, Sum: 440.5]
[GC Worker End (ms): Min: 18481711.9, Avg: 18481711.9, Max: 18481712.0, Diff: 0.1]
[Code Root Fixup: 0.0 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 1.1 ms]
[Other: 15.1 ms]
[Choose CSet: 0.0 ms]
[Ref Proc: 11.5 ms]
[Ref Enq: 0.4 ms]
[Redirty Cards: 0.4 ms]
[Humongous Register: 0.1 ms]
[Humongous Reclaim: 0.0 ms]
[Free CSet: 1.4 ms]
[Eden: 451.0M(316.0M)->0.0B(1107.0M) Survivors: 19.0M->26.0M Heap: 732.3M(2048.0M)->287.5M(2048.0M)]
[Times: user=0.49 sys=0.00, real=0.07 secs]
2021-11-05T15:14:48.726+0800: 18481.728: [GC concurrent-root-region-scan-start]
2021-11-05T15:14:48.790+0800: 18481.791: [GC concurrent-root-region-scan-end, 0.0635930 secs]
2021-11-05T15:14:48.790+0800: 18481.791: [GC concurrent-mark-start]
2021-11-05T15:14:49.056+0800: 18482.057: [GC concurrent-mark-end, 0.2661284 secs]
2021-11-05T15:14:49.056+0800: 18482.058: [GC remark 2021-11-05T15:14:49.056+0800: 18482.058: [Finalize Marking, 0.0006772 secs] 2021-11-05T15:14:49.057+0800: 18482.059: [GC ref-proc, 0.0047694 secs] 2021-11-05T15:14:49.062+0800: 18482.064: [Unloading, 0.0065857 secs], 0.0138728 secs]
[Times: user=0.06 sys=0.01, real=0.02 secs]
2021-11-05T15:14:49.071+0800: 18482.073: [GC cleanup 293M->292M(2048M), 0.0052534 secs]
[Times: user=0.03 sys=0.00, real=0.00 secs]
2021-11-05T15:14:49.076+0800: 18482.078: [GC concurrent-cleanup-start]
2021-11-05T15:14:49.076+0800: 18482.078: [GC concurrent-cleanup-end, 0.0000441 secs]
young gc
021-11-05T15:20:50.084+0800: 18843.086: [GC pause (G1 Evacuation Pause) (young), 0.0714720 secs]
[Parallel Time: 60.6 ms, GC Workers: 8]
[GC Worker Start (ms): Min: 18843087.2, Avg: 18843088.2, Max: 18843092.1, Diff: 4.9]
[Ext Root Scanning (ms): Min: 0.0, Avg: 0.3, Max: 0.7, Diff: 0.7, Sum: 2.4]
[Update RS (ms): Min: 9.2, Avg: 13.0, Max: 14.2, Diff: 5.0, Sum: 104.0]
[Processed Buffers: Min: 13, Avg: 18.9, Max: 36, Diff: 23, Sum: 151]
[Scan RS (ms): Min: 16.5, Avg: 17.0, Max: 17.2, Diff: 0.7, Sum: 136.1]
[Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
[Object Copy (ms): Min: 29.0, Avg: 29.0, Max: 29.1, Diff: 0.1, Sum: 232.1]
[Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Termination Attempts: Min: 1, Avg: 1.0, Max: 1, Diff: 0, Sum: 8]
[GC Worker Other (ms): Min: 0.0, Avg: 0.1, Max: 0.2, Diff: 0.1, Sum: 0.8]
[GC Worker Total (ms): Min: 55.5, Avg: 59.4, Max: 60.4, Diff: 4.9, Sum: 475.5]
[GC Worker End (ms): Min: 18843147.5, Avg: 18843147.6, Max: 18843147.7, Diff: 0.2]
[Code Root Fixup: 0.0 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.7 ms]
[Other: 10.2 ms]
[Choose CSet: 0.0 ms]
[Ref Proc: 4.5 ms]
[Ref Enq: 0.3 ms]
[Redirty Cards: 0.3 ms]
[Humongous Register: 0.5 ms]
[Humongous Reclaim: 0.0 ms]
[Free CSet: 3.7 ms]
[Eden: 1222.0M(1222.0M)->0.0B(1208.0M) Survivors: 6144.0K->20.0M Heap: 1476.8M(2048.0M)->268.7M(2048.0M)]
[Times: user=0.50 sys=0.00, real=0.07 secs]
当应用运行开始时,堆内存可用空间还比较大,只会在年轻代满时,触发年轻代收集;随着老年代内存增长,当到达IHOP阈值-XX:InitiatingHeapOccupancyPercent(老年代占整堆比,默认45%)时,G1开始着手准备收集老年代空间。
首先经历并发标记周期,识别出高收益的老年代分区,前文已述。但随后G1并不会马上开始一次混合收集,而是让应用线程先运行一段时间,等待触发一次年轻代收集。在这次STW中,G1将保准整理混合收集周期。接着再次让应用线程运行,当接下来的几次年轻代收集时,将会有老年代分区加入到CSet中,即触发混合收集,这些连续多次的混合收集称为混合收集周期(Mixed Collection Cycle)。
暂停时间,默认值200ms。这是一个软性目标,G1会尽量达成,如果达不成,会逐渐做自我调整。
对于Young GC来说,会逐渐减少Eden区个数,减少Eden空间那么Young GC的处理时间就会相应减少。对于Mixed GC,G1会调整每次Choose Cset的比例,默认最大值是10%,当然每次选择的Cset少了,所要经历的Mixed GC的次数会相应增加。
减少Eden的总空间时,就会更加频繁的触发Young GC,也就是会加快Mixed GC的执行频率,因为Mixed GC是由Young GC触发的,或者说借机同时执行的。 频繁GC会对对应用的吞吐量造成影响,每次Mixed GC回收时间太短,回收的垃圾量太少,可能最后GC的垃圾清理速度赶不上应用产生的速度,那么可能会造成串行的Full GC,这是要极力避免的。所以暂停时间肯定不是设置的越小越好,当然也不能设置的偏大,转而指望G1自己会尽快的处理,这样可能会导致一次全部并发标记后触发的Mixed GC次数变少,但每次的时间变长,STW时间变长,对应用的影响更加明显。
Region大小,若未指定则默认最多生成2048块,每块的大小需要为2的幂次方,如1,2,4,8,16,32,最大值为32M。Region的大小主要是关系到Humongous Object的判定,当一个对象超过Region大小的一半时,则为巨型对象,那么其会至少独占一个Region,如果一个放不下,会占用连续的多个Region。当一个Humongous Region放入了一个巨型对象,可能还有不少剩余空间,但是不能用于存放其他对象,这些空间就浪费了。所以如果应用里有很多大小差不多的巨型对象,可以适当调整Region的大小,尽量让他们以普通对象的形式分配,合理利用Region空间。
通过-XX:InitiatingHeapOccupancyPercent指定触发全局并发标记的老年代使用占比,默认值45%,也就是老年代占堆的比例超过45%。如果Mixed GC周期结束后老年代使用率还是超过45%,那么会再次触发全局并发标记过程,这样就会导致频繁的老年代GC,影响应用吞吐量。同时老年代空间不大,Mixed GC回收的空间肯定是偏少的。可以适当调高值,当然如果此值太高,很容易导致年轻代晋升失败而触发Full GC,所以需要多次调整测试。
通过-XX:G1HeapWastePercent指定触发Mixed GC的堆垃圾占比,默认值5%,也就是在全局标记结束后能够统计出所有Cset内可被回收的垃圾占整对的比例值,如果超过5%,那么就会触发之后的多轮Mixed GC,如果不超过,那么会在之后的某次Young GC中重新执行全局并发标记。可以尝试适当的调高此阈值,能够适当的降低Mixed GC的频率。
-Xmx8192m
-Xms8192m
-XX:+UseG1GC
-XX:+ExitOnOutOfMemoryError
-XX:MaxGCPauseMillis=200
-XX:+UnlockExperimentalVMOptions
-XX:G1MixedGCLiveThresholdPercent=85
-XX:G1MaxNewSizePercent=45
-XX:G1HeapWastePercent=10
-XX:InitiatingHeapOccupancyPercent=30
-verbose:gc
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/data/tmp/gc.log
参考:https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc_tuning.html#recommendations