G1 垃圾收集器

年轻代:                                                                       老年代

  Serial  单线程的复制算法                                  Serial Old

  pawNew 是Serial的多线程版本                             CMS  (最大降低了,单次垃圾的收集时间)

  Parallel Scavenge 关注的是吞吐量                   Parallel Old

  

之前的内存结构:

  

 

 G1 的内存结构:每一个region 是 1-32M

 

 那如果大对象来了,要怎么放呢?

  • 0.5region <= 对象 <1 region,这个对象会直接存储在 O区,并标记为H区(超大对象区)

  • 对象>1 region,会申请多个连续的H区来存储这个对象

Rset

  一个Region 有一个Rset : 记录其它Region引用当前Region对象

Cset 

  本次GC需清理的Region集合

 

YGC:

  采用复制算法,将E和S(from)区 复制到S(to)区,图中比较小的绿色就是 S(to)区

  

 

 没有单独的Old区GC,在old gc的时候,同时也把young区进行了gc。  因此有一个MixGC

并发标记过程:

1. 初始标记阶段: 标记从根节点直接可达的对象。 这个阶段是STW,并且会触发一次年轻代GC

2. 根区域扫描(RootRegionScan): ????

  Rset作用有哪些:  有了Rset 只需要查看所有Y区region的Rset 就知道哪些O区region跨代引用了,避免了扫描整个O区。

 

 

G1 提高效率的点有哪些:

1. 重新标记时X区域直接删除

2. Rset 降低了扫描时间

3. 重新标记阶段 使用了SATB 速度比CMS快

4. 清理过程为选取部分Region进行清理,提高了清理的效率。

 

对比CMS,有哪些不同?

1. region化的内存结构,采用复制清理方式,避免了内存碎片

2.  SATB 速度更快

3, 初始标记,并发标记,重新标记,并发清除四个阶段很像,但是G1 中有很多标记region的操作,并借助Rset进行了范围的缩小,提高了并发标记的速度。

  初始标记和YGC 的STW一起,提高了效率;

  并发标记因为rset的设计,扫描范围缩小了,提高了效率

  重新标记使用了SATB提高了效率

  清理虽然造成了STW,但是复制使内存紧凑,避免内存碎片。同时只清理垃圾较多的region,最大限度降低了STW时间。

 

遗留问题:

1. G1中的记忆集是怎么实现的

  首先产生跨代引用的场景是发生YoungGC的过程。此时新生代的对象会开始寻找根,看看自己是否属于根可达对象,从而判断自己是否是垃圾。

  但并不是所有老年代都会引用着新生代的对象,那么相对频繁的YoungGC,每次都从根节点遍历一次,效率就会被严重影响。

  卡表将整个老年代分成了多个层级,card[0]、card[1]、card[2]。如果某个card区域中的老年代对象引用着新生代的对象,那么就被叫做脏卡。当YoungGC发生时,某个新生代的对象发现其GCRoots在老年代,并进行跨代寻找的时候,只需要在对这些脏卡中的GCRoots,使用可达性分析算法,判断是否存活即可。

 

  每个Region中都存在一个Hash Table结构的记忆集,Key为其他Region的起始地址,Value是其他Card Table卡表的索引集合。

  原来卡表指向的是卡页的内存地址段,代表我引用了谁,每个Card覆盖一定范围的Heap,

  现在的记忆集,代表着谁引用了我,因此收集的过程会更复杂一点,并且需要额外的10%-20% 的堆内存空间来维持。   

  维护记忆集的方式也和卡表类似,通过写屏障来实现。

  引入标准介绍:

  卡表是:我引用了谁,CMS中,用于减少遍历Old区域

  记忆集是:谁引用了我,是一个Hashtable,key是region起始地址,value是一个集合,对应的是卡表的index,然后就可以找到对应的脏表。

  

    

2. 重新标记的时候,为什么SATB快。  (原始快照)

   之前CMS讲过了,漏标的情况是:

   灰色断开对象,然后黑色又连接上了这个对象,但是这个对象是白色的,因此在重新标记的时候并没有被标记,此时出现漏标情况。那如何搞定呢?

   具体流程:

   1. 开始时生成一个快照。标记存活对象

   2. 在并发标记的时候所有被改变的对象入对, 在写屏障里把所有旧的引用所指向的对象都变成非白色的。

   3.  可能会存在浮动垃圾,将在下次被收集。

    例如 A.b =B,C.b = null  在并发标记中 发生了 A.b = null,C.b =B。 那么这个时候由于旧的引用A所指向的对象是B,所以将B标为非白。

   那如何找到GC过程中新分配的对象呢?

    

    SATB再重新标记环节只需要去扫描那些被入队的引用,并配合Rset来判断当前对象是否被引用来进行回收;

    而增量更新还需要再扫描一遍;

 

4. mix GC和young gc 到底是个怎么样的流程:

    young GC  回收的是所有年轻代的Region。当E区不能再分配新对象时就会触发。采用复制算法将E区和S(from区)复制到 S(to)区。

 

posted @ 2022-08-14 23:42  小罗咯  阅读(199)  评论(0编辑  收藏  举报