jvm深度学习(12):G1中的技术细节、安全点与安全区域

G1 中的技术细节

前言:前面在JVM中常见的垃圾回收器章节对G1有过详细的描述。我们知道G1为了解决STW问题,使用了“化整为零”的思想。将堆内存分割小块的region,每个region根据需要,可以是Eden区或者Survivor或者老年代区。G1根据区域的不同,用不同的策略进行垃圾回收。

 

问题

        虽然这种“化整为零”很好的解决了STW问题,但是随着内存区域的颗粒化,再加上G1内存区域的不固定(回收前Eden,但由于都处于强引用,回收不了,直接变为Survivor,更有甚者直接老年代),必将导致跨代引用增多,这就导致我们在扫描新生代时,也要去扫整个老年代。

 

PS:跨代引用 

         堆空间通常被划分为新生代和老年代。由于新生代的垃圾收集通常很频繁,如果老年代对象引用了新生代的对象,那么回收新生代的话,需要跟踪从老 年代到新生代的所有引用,所以要避免每次 YGC 时扫描整个老年代,减少开销。

 

解决

先认识下RSetCardTable

RSet(记忆集):

        记录了其他 Region 中的对象到本 Region 的引用,RSet 的价值在于使得垃圾收集器不需要扫描整个堆,找到谁引用了当前分区中的对象,只需要扫描 RSet 即可。RSet 本身就是一个 Hash 表,如果是在 G1 的话,则是在一个 Region 区里面。

 

CardTable

        由于做新生代 GC 时,需要扫描整个 OLD 区,效率非常低,所以 JVM 设计了 CardTable,如果一个 OLD 区 CardTable 中有对象指向 Y 区, 就将它设为 Dirty (标志位 1), 下次扫描时,只需要扫描 CARDTABLE 上是 Dirty 的内存区域即可。字节数组 CARDTABLE 的每一个元素都对应着其标识的内存区域中一块特定大小的内存块,这个内存块被称作“卡页”(Card Page)。 一般来说,卡页大小 都是以 2 的 N 次幂的字节数,假设使用的卡页是 2 的 10 次幂,即 1M,内存区域的起始地址是 0x0000 的话,数组 CARD_TABLE 的第 0、1、2 号元素,分别 对应了地址范围为 0x0000~0x03FF、0x0400 ~ 0x07FF、0x0800~0x011FF 的卡页内存.

结合使用如图:

通过CardTable我们可以迅速定位哪些区域存在跨代引用,再通过RSet获取引用关系,这极大的提高了垃圾回收效率。

 

小结:

        这里描述的是 G1 处理跨代引用的细节,其实在 CMS 中也有类似的处理方式,比如 CardTable,也需要记录一个 RSet 来记录,我们对比一下,在 G1 中是每 一个 Region 都需要一个 RSet 的内存区域,导致有 G1 的 RSet 可能会占据整个堆容量的 20%乃至更多。但是 CMS 只需要一份,所以就内存占用来说,G1占用的内存需求更大,虽然 G1 的优点很多,但是我们不推荐在堆空间比较小的情况下使用 G1,尤其小于 6 个 G。

 

小提问:是不是只要有跨代引用就会有rset表?
解答:可以没有reset,但是效率会低很多,卡表倒是一般都会有。
 

 

安全点与安全区域

        安全点与安全区域都在STW前,不同的垃圾回收器有不同的STW的阶段,除了cms和G1,其他的传统垃圾回收器全阶段都需要STW。

如图:

安全点

        用户线程暂停,GC 线程要开始工作,但是要确保用户线程暂停的这行字节码指令是不会导致引用关系的变化(比如刚好在new这个关键字,你暂停了,这个对象是有还是没有,这个对象有没有引用关联着,引用有变化的都比较麻烦处理)。所以 JVM 会在字节码指令中,选一些指令, 作为“安全点”,比如方法调用循环跳转异常跳转等,一般是这些指令才会产生安全点。
        为什么它叫安全点,是这样的,GC 时要暂停业务线程,并不是抢占式中断(立马把业务线程中断)而是主动是中断。
        主动式中断是设置一个标志,这个标志是中断标志,各业务线程在运行过程中会不停的主动去轮询这个标志,一旦发现中断标志为 True,就会在自己最近 的“安全点”上主动中断挂起。

 

安全区域

        为什么需要安全区域?
        要是业务线程都不执行(业务线程处于 Sleep 或者是 Blocked 状态),那么程序就没办法进入安全点,对于这种情况,就必须引入安全区域。
       安全区域是指能够确保在某一段代码片段之中, 引用关系不会发生变化,因此,在这个区域中任意地方开始垃圾收集都是安全的。我们也可以把安全区 城看作被扩展拉伸了的安全点。

图解:

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值