垃圾回收器(二):G1

堆空间

  • 自由分区(Free Heap Region,FHR)
  • 新生代分区(Young Hreap Region,YHR)
    • E 是 eden region
    • S 是 survivor region
  • 老年代分区(Old Heap Region,OHR)
    • 如果一个对象占用的空间超过了分区容量50%以上,G1收集器就认为这是一个巨型对象
    • 大对象分区(Humongous Heap Region,HHR)
      • 短期存在的巨型对象
      • G1 只决定它们是否生存,回收他们占用的空间,从不会移动它们
      • 可以跨越多个连续regions。直接分配到老年代,防止反复拷贝移动
      • 在global concurrent marking阶段的cleanup 和 full GC阶段回收
      • 在分配H-obj之前先检查是否超过 initiating heap occupancy percent和the marking threshold, 如果超过的话,就启动global concurrent marking,为的是提早回收,防止 evacuation failures 和 full GC
      • Young-Only 阶段,humongous regions 可能会被回收
      • Space-Reclamation,humongous regions 可能会被回收
      • 为了减少连续H-objs分配对GC的影响,需要把大对象变为普通的对象,建议增大Region size。
      • 一个Region的大小可以通过参数-XX:G1HeapRegionSize设定,取值范围从1M到32M,且是2的指数

GC

  • G1提供了两种GC模式,Young GC和Mixed GC,两种都是完全Stop The World的
  • Young GC:选定所有年轻代里的Region。
  • Mixed GC:选定所有年轻代里的Region,外加根据global concurrent marking统计得出收集收益高的若干老年代Region。在用户指定的开销目标范围内尽可能选择收益高的老年代Region。Mixed GC不是full GC,它只能回收部分老年代的Region
  • 如果mixed GC实在无法跟上程序分配内存的速度,导致老年代填满无法继续进行Mixed GC,就会使用serial old GC(full GC)来收集整个GC heap。G1是不提供full GC的。如果堆是足够大的,Mixed gc 没有回收足够的 old region,或者 concurrent mark 没法及时完成,都可能会导致 full gc。
  • 在几次gc后,old gen 的对象占有比超过了 InitiatingHeapOccupancyPercent,gc就会进入并发标记准备(concurrent mark)。Mixed gc 依赖 concurrent mark
  • G1默认当分区内存占用阈值达到总内存的45%,会发生Mixed gc(混和GC)

GC 流程

YGC流程:

  1. 挂起所有用户线程,应用程序暂时不能向外提供响应(STW)
  2. 计算需要收集的区间(CSet),YGC期间,仅回收Y区,所以所有的Y区就是CSet
  3. 进行根处理,包含JVM根和Java根。为了扫描全堆,这里只需要把RSet记录的对象加入根即可
  4. JIT代码扫描等,根据栈中的对象进行递归遍历复制对象
  5. 因为对象已经有挪动,更新JIT代码中指针存储的对象地址
  6. 引用处理,一些软、弱、虚、析构(FinalReference)引用等的处理
  7. 字符串去重等处理
  8. 清理卡表,也就是把全局卡表中已经处理过的分区的卡表清空
  9. 进行Redirty操作,也就是重构RSet。释放CSet区
  10. 尝试回收大对象,如果某个大对象所在的分区没有RSet引用,说明这个大对象已经死亡,可以直接回收
  11. 尝试扩展内存,参数有GCTimeRatio和GExpandByPercentOfAvailable来决定是否需要扩展,前者在G1中默认值是9,代表的意思是GC占用的时间必须小于1/(1+9),也就是10%,这个值在之前的垃圾收集器默认值是99。如果吞吐量不达标,就会尝试扩展内存,大小由GExpandByPercentOfAvailable决定,默认20,也就是未提交内存的20%
  12. 如果满足条件的,触发并发标记周期;判断方式是YGC之后,老年代内存占总内存超过一定阈值(参数-XX:InitiatingHeapOccupancyPercent决定,默认45%)触发。

混合回收:

  • 根扫描,初始标记:并发标记周期之前一定有一次YGC,所以初始标记会把这次YGC的存活对象也加入根,还有其他根对象,如:栈对象、全局静态对象、JNI对象等等
  • 并发标记(concurrent-mark-start~end之间):因为存活对象会比较多,所以这块耗时会比较久,CMS、G1等的这部肯定都是"并发执行的",要不过长的STW时间,会一定程度上的导致服务运行。并且并发标记过程是涉及所有区的,所有老年代区的对象都参与标记。在标记的过程中也会计算每个区的存活对象数目和字节数。
  • 再标记:再标记过程是有STW。再标记的目的是处理哪些在并发标记过程中有引用关系变更的对象,见"2.c并发标记的难点"。
  • 清理:清理阶段会统计存活对象,并且按照结果对区维度进行排序,以便后续mixed-gc的CSet的选择。同时和会重置RSet,因为老年代的标记已经完成了,这个时候需要删除原来RSet里面保存的引用关系。
相关推荐
爱丽_2 小时前
AQS 的 CLH 同步队列:入队/出队、park/unpark 与“公平性”从哪来
java·开发语言·jvm
Barkamin2 小时前
JVM核心简单介绍
jvm
Rick19933 小时前
JVM 高频10问
jvm
皙然3 小时前
AQS模型详解:Java并发的核心同步框架(从原理到实战)
java·开发语言·jvm
愤豆3 小时前
08-Java语言核心-JVM原理-垃圾收集详解
java·开发语言·jvm
南境十里·墨染春水3 小时前
C++传记 this指针 及区分静态非静态成员(面向对象)
开发语言·jvm·c++·笔记
DJ斯特拉4 小时前
JUC基础
java·jvm·juc
小年糕是糕手4 小时前
【35天从0开始备战蓝桥杯 -- Day7】
开发语言·jvm·数据库·c++·蓝桥杯
2401_8735449214 小时前
使用Python进行PDF文件的处理与操作
jvm·数据库·python