分代垃圾回收算法

由来(年龄)

根据经验“大部分对象在生成后马上就变成了垃圾,很少有对象能活得很久”。
分代垃圾回收利用该经验,在对象中导入“年龄”概念,经历过一次GC后活下来的对象年龄为1岁。
分代GC通过年龄对对象进行分代管理,在年轻代频繁执行GC(高频),老年代仅在需要时才执行GC(低频)。

分代

分代垃圾回收把对象分类成几代,针对不同的代使用不同的GC算法,
我们把刚生成的对象称为新生代对象 ,达到一定年龄的对象称为老年代对象。
新生代GC(minor GC):大部分新生代对象都没存活下来,GC在短时间内就结束了 。
老年代GC(major GC):因为老年代很少变成垃圾,因此减少对老年代对象的GC。

晋升

新生代GC将存活了一定次数的新生代对象转变为老年代对象。

Ungar的分代垃圾回收

堆的结构

0
Eden区域:新对象直接在此区域分配内存。
From区域:存储上次minor GC后存活的新生代对象。
To区域:存储下次minor GC后存活的新生代对象。
minor GC会将Eden区域和From区域中存活的对象复制到To区域。每次minor GC后都会将From区域和To区域互换。新生代使用了复制算法。
Tenuring区域:老年代区域,minor GC中存活对象年龄超过阈值会晋升到Tenuring区域。

记录集

缘由

分代垃圾回收的优点是只将垃圾回收的重点放在新生代对象身上,以此来缩减GC所需要的时间。
新生代GC采用复制算法,因此需要修改其他对象对新生代对象引用的地址。

用途

记录集用来记录从老年代到新生代对象的引用。在记录集里会记录发出引用的对象。这样在搜索记录集时能更新对新生代对象的引用地址。
0

写入屏障

在mutator更新对象间的指针的操作中,写入屏障生效。
1、发出引用的对象是不是老年代对象
2、指针更新后的引用的目标对象是不是新生代对象
3、发出引用的对象是否还没有被记录到记录集中
当这些检查结果为真时,obj就会被记录到记录集中

新生代GC

使用复制算法
遍历GC根和记录集,如果其引用的对象在新生代中则进行复制,否则不进行处理。
在GC 过程中需要维护GC年龄、forwarding指针、remembered 标记、记录集。
在复制时如果对象的年龄未达到阈值则更新年龄并在新生代复制对象更新forwarding指针;否则将对象晋升至老年代,遍历其子结点,若存在对新生代对象的引用则将其加入记录集。
遍历GC根,对于新生代中的对象进行复制,并递归复制子对象。
遍历记录集,对于复制完子对象的对象判断其子对象是否均在老年代中,若是在记录集中删除该对象。

老年代GC

使用标记-清除算法

优点

通过使用分代垃圾回收,可以改善GC所花费的时间(吞吐量)。

缺点

“很多对象年纪轻轻就会死”并不适用于所有程序。
写入屏障导致的额外负担降低了吞吐量。

卡片标记——记录各代之间的引用的方法

将老年代空间按照相等的大小分割开来,分割出来的一个个空间被称为卡片。
另外,我们为每个卡片准备一个与其对应的标记位,并将这个位作为标记表格进行管理(通过写入屏障)。
GC时会寻找位图表格。当找到设置了标志位的卡片时,就会从卡片开头开始寻找指向新生代空间的引用。

优点

能有效利用内存空间,另外无论从老年代指向新生代空间的引用怎么增加,都不会出现记录集那样的内存溢出。

缺点

如果在标记表格里设置了很多位,就可能会在搜索卡片上花费大量时间。本质上是一种以时间换空间的做法。
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2022-07-14 11:21  bavaria  阅读(261)  评论(0)    收藏  举报