JVM学习总结—— 八、JVM中G1具体回收过程

G1垃圾收集器

G1回收器名字由来:G1根据每个Region分区回收垃圾的价值维护一个优先级列表,
                                根据用户设定的允许收集器停顿时间,有先处理价值收益高的Region。 


一、创建对象分配策略

1. TLAB(Thread Local Allocation Buffer) 线程本地分配缓冲区

2. Eden区中分配

3. Humongous区分配

Humongous:如果一个对象占用的空间超过了分区容量75%以上,G1收集器就认为这是一个巨型对象。
这些巨型对象,默认直接会被分配在年老代,但是如果它是一个短期存在的巨型对象,就会对垃圾收集器造成负面影响。
为了解决这个问题,G1划分了一个Humongous区,它用来专门存放巨型对象。
如果一个H区装不下一个巨型对象,那么G1会寻找连续的H分区来存储。为了能找到连续的H区,有时候不得不启动Full GC。

二、对象是否符合回收

说白就是判断对象是否还存在引用关系。
1. 强引用(new指令生成的)

2. 软引用(还有用但非必须对象,在系统溢出异常前会对这些对象回收,回收后内存仍然不足抛出异常)

3. 弱引用(下次回收一定能回收的对象引用关系)

4. 虚引用(系统回收对象时收到一个系统通知))

三、垃圾收集类型和算法

划分为两大类
1.引用计数式垃圾收集(直接垃圾收集)

2.追踪垃圾收集(间接垃圾收集)

具体算法
1.引用计数算法(给对象添加一个计数器,多一个引用计数器+1、
   少一个引用计数器-1 虽然占用了额外内存空间原理简单高效 例如:Python中squirrel使用) 
 注意:无法处理循环引用的问题,引用计数法不适合JVM的垃圾回收

2.可达性分析算法(通过 GC Roots 根据引用关系向下搜索,搜索路径被称为引用链。如果对象到GC Roots没有引用链存在就可以判     定为可回收对象 并不一定立即回收需要两次标记过程)

四、Young GC

 Young GC 阶段:
 阶段1:初始标记
 阶段2:并发标记
 阶段3:最终标记
 阶段4:筛选回收
 阶段5:重置线程
 

Young GC主要是对Eden区进行GC,它在Eden空间耗尽时会被触发。
在这种情况下,Eden空间的数据移动到Survivor空间中。
如果Survivor空间不够,Eden空间的部分数据会直接晋升到年老代空间。
Survivor区的数据移动到新的Survivor区中,也有部分数据晋升到老年代空间中。
最终Eden空间的数据为空,GC停止工作,应用线程继续执行。

如果仅仅GC 新生代对象,我们如何找到所有的根对象呢? 老年代的所有对象都是根么?

G1引进了RSet(记忆卡)的概念:它的全称是Remembered Set是用于记录从非收集区域指向收集区域的指针集合。

RSet其实是一个Hash Table,Key是别的Region的起始地址,Value是一个集合,里面的元素是Card Table的Index。

需要注意的是,引用的对象很多需要对每个引用做处理,在G1 中又引入了另外一个概念,卡表(Card Table)。

卡表:将一个分区在逻辑上划分为固定大小的连续区域,每个区域称之为卡页。

卡页也通常较小,介于0到512字节之间 (2的n次幂)。
Card Table通常为字节数组,由Card的索引(即数组下标)来标识每个分区的空间地址。

默认情况下,每个卡都未被引用(标记为0)。
当一个地址空间被引用时,这个地址空间对应的数组索引的值被标记为”1″,即标记为被引用。

此外RSet也将这个数组下标记录下来。将Rset添加到GCRoots中一并扫描

GC Roots 根据引用关系向下搜索过程

类加载完成时,Hotspot使用OopMap数据结构会把对象内什么偏移量上什么类型计算处理,在即时编译过程中也会在特定位置记录下栈里和寄存器里那些位置引用记录下来。

在OopMap协助下,可以快速完成GC Roots遍历

GC Roots遍历时先中断所有用户线程
如果用户线程中断的地方不在安全点就会恢复线程跑到最近安全点在重新中断。
如果线程处于sleep或blocked状态显然不能等待线程走到安全点,JVM会建立安全区保证弄一段代码段中引用关系不会发生改变。
GC Roots遍历完成后发出信号,用户线程才能离开安全区或安全点。

记忆卡缩小了GC Roos扫描范围问题,如何解决卡表元素维护问题?例如:何时标识改为1,谁来改。
何时标识改为1:其他分区中对象引用本区域对象时,对象引用类型字段赋值那一刻。
通过写屏障技术维护卡表状态,写屏障可以看作在虚拟机层面对“引用类型字段赋值”这个操作的AOP切面。
这个操作带来两个问题
1.额外开销,但是比minor GC 扫描老年代低的多。
2.卡表高并发场景面临的“伪共享”。(解决办法先检查卡表标记,只有卡表元素未被标记才更改标记)
    JDK1.7后 Hotspot 参数-XX:+UseCondCardMark 参数决定是否开启卡表更新条件判断。解决伪共享问题会带来额外开销。
   


五、G1 Mixed GC

Mixed GC不仅进行正常的新生代垃圾收集,同时也回收部分后台扫描线程标记的老年代分区。

#GC步骤分2步:
1.全局并发标记(global concurrent marking)
2.拷贝存活对象(evacuation)


global concurrent marking的执行过程是怎样的呢?

1.初始标记(initial mark,STW):在此阶段,G1 GC 对根进行标记。该阶段与常规的 (STW) 年轻代垃圾回收密切相关。

2.根区域扫描(root region scan):G1 GC 在初始标记的存活区扫描对老年代的引用,并标记被引用的对象。
                                  该阶段与应用程序(非 STW)同时运行,并且只有完成该阶段后,才能开始下一次 STW 年轻代垃圾回收。

3.并发标记(Concurrent Marking):G1 GC 在整个堆中查找可访问的(存活的)对象。该阶段与应用程序同时运行,可以被 STW 年轻代垃圾回收中断

4.最终标记(Remark,STW):该阶段是 STW 回收,帮助完成标记周期。G1 GC 清空 SATB 缓冲区,跟踪未被访问的存活对象,并执行引用处理。

5.清除垃圾(Cleanup,STW):在这个最后阶段,G1 GC 执行统计和 RSet 净化的 STW 操作。
                            在统计期间,G1 GC 会识别完全空闲的区域和可供进行混合垃圾回收的区域。
                清理阶段在将空白区域重置并返回到空闲列表时为部分并发。

并发标记,我们不得不了解并发标记的三色标记算法。它是描述 追踪垃圾收集 的一种有用的方法

1.黑色:根对象,或者该对象与它的子对象都被扫描
2.灰色:对象本身被扫描,但还没扫描完该对象中的子对象
3.白色(注意两个含义):未被扫描对象,扫描完成所有对象之后,最终为白色的为不可达对象,即垃圾对象

当GC开始扫描对象过程
1.根对象被置为黑色,子对象被置为灰色。
2.继续由灰色遍历,将已扫描过的子对象的对象置为黑色。
3.遍历了所有可达的对象后,所有可达的对象都变成了黑色。不可达的对象即为白色,需要被清理
4.如果在标记过程中,应用程序也在运行,那么对象的指针就有可能改变。这样的话,我们就会遇到两个问题:1.对象丢失问题。2.有的对象可以跳过这次回收被称为浮动垃圾。
 (例如:标记为白色对象引用到黑色对象下边,很有可能白色没有被扫描到 这样被回收了很不合理)
 
 GC标记的对象丢失?
1.赋值器插入一条或多条重黑色对象到被白色对象的新引用。
2.赋值器删除全部从灰色对象到白色对象的直接或间接引用。

解决方式:
1.增量更新(Incremental update)
   (新增引用关系添加时,记录下来等并发扫描结束后,重新将黑色对象作为根节点重新扫描一次)
2.原始快照 SATB(snapshot-at-the-beginning)
  (删除引用关系时记录下来,等并发扫描结束后,重新将灰色对象作为根节点重新扫描一次)

这些记录的操作都是通过写屏障AOP实现的。

CMS采用的是增量更新(Incremental update)

G1中使用的是SATB(snapshot-at-the-beginning)


GC Roots包含:
1)虚拟机栈(栈帧中的局部变量表)中对象的引用。JVM会通过(GC Roots)局部变量表,使用可达性分析算法扫描对象,进行gc。
2)方法区中,类静态属性的引用。
3)方法区中,常量对象的引用。
4)本地方法栈中,JNI(native方法)对象的引用。
5)HotSpot中,使用OopMap数据结构存储对象内偏移量对应的数据类型,在JIT编译时,在安全点(safe point)记录栈和寄存器中的引用和对应的位置。
6)Rset
7)并发标记中的黑色对象或灰色对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术分子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值