Java虚拟机2 G1垃圾回收详解, 参数, 日志

Java虚拟机 系列文章

Java虚拟机1 内存管理、GC,包括 Shenandoah ZGC
Java虚拟机2 G1垃圾回收详解, 参数, 日志 (本文)
Java虚拟机3 Class文件及类加载
Java虚拟机4 方法调用原理、动态类型支持
Java虚拟机5 编译与优化
Java虚拟机6 内存模型、线程、锁

总结 Java 不支持的语法特性
Java 协程:Loom Project 实战
其他JVM语言

垃圾回收(GC)算法

哪些对象需要被回收?
引用计数
可达性分析

回收垃圾对象
标记清除 Mark-Sweep
标记复制 Mark-Copy
标记整理 Mark-Compact

分代收集
新生代(Young)、老年代(Old)

并行(Parallel)与并发(Concurrent)

其他GC概念
根节点(Root)
安全点(Safe-Point)
记忆集(R-Set)
写屏障/读屏障
三色标记法

分配内存
指针碰撞
空闲链表

G1 垃圾回收(Garbage-First)

官方介绍
https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html

堆内存
在这里插入图片描述
G1采用分代回收,将整个堆拆成多个分区(Heap Region)。一个分区既可以充当新生代可也以充当老年代。
G1的分区类型(HeapRegionType)大致可以分为四类:

  • 自由分区(Free Heap Region,FHR)
  • 新生代分区(Young Heap Region,YHR)
  • 大对象分区(Humongous Heap Region,HHR)
  • 老生代分区(Old Heap Region,OHR)

其中新生代分区又可以分为Eden和Survivor;大对象分区又可以分为大对象头分区和大对象连续分区。
每个分区大小相同,区间为[1M, 32M], 且为 2 n 2^{n} 2n。默认分为2048个分区。
大对象:大于单个分区的一半。

三色并发标记

新生代回收(Young GC)
回收整个新生代
并行复制算法
会动态改变新生代大小

混合回收(Mixed GC)
回收整个新生代和部分老年代
优先回收垃圾多的老年代
并行复制算法

Full GC
回收全部分区

G1停顿预测模型
期望停顿时间: MaxGCPauseMillis,默认200ms,尽量在这个停顿时间内。
根据历史数据计算本次收集的分区数量。
期望停顿时间越小,新生代空间越小。

记忆集
记录分区之间的引用关系(谁引用我)
用到写屏障

参数

注: *标记的为实验选项,需要打开 -XX:+UnlockExperimentalVMOptions

参数默认值说明优化
xms初始堆大小根据业务设置
xmx最大堆大小根据业务设置
+UseG1GC开启G1 GC
堆内存
MaxGCPauseMillis200ms最大停顿时间,不是硬性条件根据业务设置
G1HeapRegionSize0设置Region大小,[1M,32M]不设置时启发式推断可以逐步验证设置
G1NewSizePercent5新生代最小百分比一般不设置,影响暂停时间
G1MaxNewSizePercent60新生代最大百分比一般不设置,影响暂停时间
GCTimeRatio9GC与应用程序之间的时间占比可以逐步验证设置
G1ExpandByPercentOfAvailable20一次扩展的比例可以逐步验证设置
G1ReservePercent10用于对象晋升到老年代的保留内存比例,最大为50可以逐步验证设置
*G1NewSizePercentEden分区占比
GCPauseIntervalMillisGC0GC间隔时间,不设置会启发式推断
G1ConfidencePercentGC预测置信度,越小代表预测越准确
新生代回收
ParallelGCThreadsSTW期间,并行GC线程数,会根据CPU核数推断
MaxTenuringThreshold15达到该年龄时晋升到老年代,最大为15可以逐步验证设置
G1RsetScanBlockSize64扫描记忆集时一次处理的量
SurvivorRatio8Eden和一个Survivor的比例,会影响Survivor大小
TargetSurvivorRatio50期望Survivor大小比例,增大该值会降低晋升到老年代概率
ParGCArrayScanChunk50对象数组每次遍历长度阈值
+G1EagerReclaimHumongousObjectstrue是否在YGC时回收大对象,可以关闭
+G1EagerReclaimHumongousObjectsWithStaleRefstrue判定收集哪些大对象,false表示只有记忆集引用数为0才收集
并发标记
ConcGCThreads0并发标记线程数,不设置则动态调整
InitiatingHeapOccupancyPercent45触发并发标记的整个堆使用率阈值
G1ConcMarkStepDurationMillis10并发标记子阶段每次最多执行时间可以逐步验证设置
G1SATBBufferSize1K表示每个原始快照队列最多存放1000个灰色对象
G1SATBBufferEnqueueingThresholdPercent60队列过滤后超过该阈值则新分配一个队列
MarkStackSize4M并发标记子阶段中用到的标记栈的大小,不设置则启发式推断
MarkStackSizeMax512M并发标记子阶段中用到的标记栈的大小,不设置则启发式推断
GCDrainStackTargetSize64一次标记的最多对象个数
混合回收
HeapSizePerGCThread64M可以简单地理解为每64M分配一个线程
-UseDynamicNumberOfGCThreadsfalse是否动态调整GC线程数
-ForceDynamicNumberOfGCThreadsfalse是否动态调整GC线程数
G1MixedGCLiveThresholdPercent85判断分区能否加入CSet,低于该百分比则加入
G1HeapWastePercent5CSet中可回收空间比例大于改值才会开始混合收集
G1MixedGCCountTarget8值越大,收集老年代分区越少
G1OldCSetRegionThresholdPercent10表示一次最多收集10%的分区
ClassUnloadingWithConcurrentMarktrue打开表示在并发标记的时候可以卸载已经加载的类
TLAB该类参数一般不设置
+UseTLABtrue是否开启TLAB
TLABSizeTLAB大小
TLABWasteTargetPercent1TLAB可占用的Eden空间的百分比线程数很多可以增大
TLABRefillWasteFraction64TLAB允许浪费的比例
TLABWasteIncrement4动态的增加浪费空间的字节数
MinTLABSize2kTLAB最小值,可以根据实际应用设置
+ResizeTLABtrue是否允许自动调整TLAB大小
PLAB
+ResizePLABtrue是否自动调整PLAB大小可以关闭
YoungPLABSize4096新生代PLAB缓存大小可以减小
OldPLABSize1024老年代PLAB缓存大小可以增大
ParallelGCBufferWastePct10PLAB缓存可浪费比例
记忆集该类参数一般不设置
G1ConcRefinementThreads0
G1UpdateBufferSize256
+G1UseAdaptiveConcRefinementtrue
G1RSetUpdatingPauseTimePercent10
G1ConcRefinementThresholdStep0
G1ConcRefinementServiceIntervalMillis300
G1ConcRefinementGreenZone0
G1ConcRefinementYellowZone0
G1ConcRefinementRedZone0
G1ConcRSLogCacheSize10
G1ConcRSHotCardLimit4
G1RSetRegionEntries0
引用
+ParallelRefProcBalancingEnabledtrue同一引用类型多个队列之间的均衡
-ParallelRefProcEnabledfalse是否并发处理引用,可以打开
+RegisterReferencestrue遍历对象是判断引用类型是否可回收,一般不设置
*+G1UseConcMarkReferenceProcessingtrue是否在并发标记的时候标记引用
RefDiscoveryPolicy00或1,配1表示引用对象里面的对象在处理范围内时,也处理该引用对象
SoftRefLRUPolicyMSPerMB1000软引用存活时间,1000表示每MB的内存将会存活1s
字符串去重
-UseStringDeduplicationfalse是否打开字符串去重验证有效后再打开
StringDeduplicationAgeThreshold3控制字符串是否参与去重的阈值
打印日志
+PrintGCGC 基本信息
+PrintGCDetailsGC 详细信息
*G1LogLevel=finestGC 最详细信息
+PrintGCApplicationConcurrentTime打印程序执行时间
+PrintGCApplicationStoppedTime打印停顿时间
+PrintAdaptiveSizePolicy打印参数自动设置
+PrintCommandLineFlags打印设置过的参数
+PrintTLAB跟踪TLAB使用情况
+G1TraceConcRefinement记忆集线程工作情况
+G1SummarizeRSetStats记忆集信息
*+G1TraceEagerReclaimHumongousObjects大对象收集信息
+PrintTenuringDistribution对象年龄信息
+PrintReferenceGC引用GC信息
+G1PrintHeapRegions内存的分配和使用情况
+PrintGCTimeStamps每条日志附加时间戳(程序启动到现在的时间)
+PrintGCDateStamps每条日志附加当前时间
其他
-DisableExplicitGC禁止显式调用GC
+OmitStackTraceInFastThrowtrue同一位置连续抛出异常时快速抛出,此时没有异常堆栈
+AlwaysPreTouch程序启动时分配所有物理内存,而不是使用时再分配
+UnlockExperimentalVMOptions开启实验选项

触发 Full GC 可能有这几个原因:

  • 没有足够的空间用于晋升,可:

  • 增加-XX:G1HeapRegionSize。

  • 增加-XX:G1ReservePercent选项的值(并相应增加总的堆大小),为“目标空间”增加预留内存量。

  • 并发标记不够及时,垃圾没有及时回收,所以调整的思路应该是尽早启动并发标记,让并发标记尽早完成,可:

  • 通过减少- XX:InitiatingHeapOccupancyPercent提前启动标记周期。

  • 也可以通过增加- XX:ConcGCThreads选项的值来增加并行标记线程的数目。

  • 增加- XX:G1MixedGCCountTarget的值,使得老生代回收的分区减少。

  • 减少- XX:G1ConcMarkStepDurationMillis的值,让并发标记更频繁,Remark时间更短等。

日志

// young 表示新生代回收,STW时间为 0.0170949 secs
2020-05-27T13:01:38.244+0800: 251872.929: [GC pause (G1 Evacuation Pause) (young), 0.0170949 secs]
   // 并行GC线程,13个,时间为15.9ms
   [Parallel Time: 15.9 ms, GC Workers: 13]
      // Diff:这13个线程开始最大时间差,反应进入安全点的情况
      [GC Worker Start (ms): Min: 251872929.6, Avg: 251872929.7, Max: 251872929.7, Diff: 0.1]
	  // 根扫描时间
      [Ext Root Scanning (ms): Min: 0.7, Avg: 0.9, Max: 2.1, Diff: 1.4, Sum: 11.7]
	  // 更新记忆集时间
      [Update RS (ms): Min: 0.7, Avg: 1.8, Max: 2.0, Diff: 1.3, Sum: 23.8]
	     // buffer 个数
         [Processed Buffers: Min: 8, Avg: 19.5, Max: 37, Diff: 29, Sum: 253]
	  // 扫描记忆集查找被引用的对象
      [Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
	  // 扫描JIT编译代码中引用
      [Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
	  // 存活对象复制到新分区
      [Object Copy (ms): Min: 12.9, Avg: 12.9, Max: 12.9, Diff: 0.1, Sum: 167.9]
	  // 停止GC线程时间
      [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: 13]
	  // 并行处理时其他处理花费的时间
      [GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.3]
	  // 并行GC花费的总体时间
      [GC Worker Total (ms): Min: 15.6, Avg: 15.7, Max: 15.7, Diff: 0.1, Sum: 203.8]
	  // Diff: GC线程结束最大时间差
      [GC Worker End (ms): Min: 251872945.3, Avg: 251872945.3, Max: 251872945.4, Diff: 0.0]
   // 修复和清理Code Root
   [Code Root Fixup: 0.0 ms]
   [Code Root Purge: 0.0 ms]
   // 清除记忆集中的卡表
   [Clear CT: 0.4 ms]
   [Other: 0.9 ms]
      // 选择回收区域, YoungGC是0
      [Choose CSet: 0.0 ms]
	  // 处理引用
      [Ref Proc: 0.3 ms]
	  // 引用重新加入队列
      [Ref Enq: 0.0 ms]
	  // 重构记忆集
      [Redirty Cards: 0.2 ms]
	  // 处理大对象
      [Humongous Register: 0.0 ms]
	  // 回收大对象
      [Humongous Reclaim: 0.0 ms]
	  // 释放已回收的记忆集
      [Free CSet: 0.0 ms]
   // Eden变为0,下一次使用空间为1184.0M, Survivors为 49152K, 整个堆变为523M
   [Eden: 944.0M(944.0M)->0.0B(944.0M) Survivors: 49152.0K->49152.0K Heap: 1467.7M(2048.0M)->523.0M(2048.0M)]
   
 // user  GC 线程使用 CPU 时间
 // sys   内核使用 CPU 时间
 // real  从开始到结束总时间
 // user 和 sys 为每个线程使用的时间总和,所以可能大于 real
 [Times: user=0.13 sys=0.08, real=0.02 secs] 
 
 
 // initial-mark 表示此次YGC后开始并发标记
 2020-05-24T15:03:59.990+0800: 14.675: [GC pause (G1 Evacuation Pause) (young) (initial-mark), 0.0473590 secs]
 
 
 // 开始并发标记根扫描
 2020-05-24T15:04:00.037+0800: 14.723: [GC concurrent-root-region-scan-start]
 // 根扫描结束
 2020-05-24T15:04:00.080+0800: 14.766: [GC concurrent-root-region-scan-end, 0.0431292 secs]
 // 并发扫描整个堆
 2020-05-24T15:04:00.080+0800: 14.766: [GC concurrent-mark-start]
 // 扫描结束
 2020-05-24T15:04:00.081+0800: 14.766: [GC concurrent-mark-end, 0.0001221 secs]
 // 再标记、处理引用和类卸载,  会STW
 2020-05-24T15:04:00.081+0800: 14.766: [GC remark 2020-05-24T15:04:00.081+0800: 14.766: [Finalize Marking, 0.0008773 secs]  2020-05-24T15:04:00.082+0800: 14.767: [GC ref-proc, 0.0008966 secs] 2020-05-24T15:04:00.083+0800: 14.768: [Unloading, 0.0100973 secs], 0.0121943 secs]
 [Times: user=0.14 sys=0.00, real=0.01 secs] 
 // 清除,调整记忆集, 会STW
 2020-05-24T15:04:00.093+0800: 14.779: [GC cleanup 104M->104M(2048M), 0.0009312 secs]
 [Times: user=0.00 sys=0.00, real=0.00 secs] 
 
 // mixed表示混合回收  
 2020-05-27T14:38:36.037+0800: 257690.722: [GC pause (G1 Evacuation Pause) (mixed), 0.0614190 secs]
 
 
 // 内存分配失败导致 FULL GC
 Full GC (Allocation Failure)
 [Eden: 3072.0K(194.0M)->0.0B(201.0M) Survivors: 0.0B->0.0B Heap: 3727.1M(4022.0M)->3612.0M(4022.0M)], [Metaspace: 2776K->2776K(1056768K)]

请添加图片描述
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值