JVM垃圾回收器详解:新生代内存管理适用于单线程的复制回收算法

适用于单线程的复制回收算法

在前面介绍了复制算法的思想,但并未涉及具体的实现。实现中通常要考虑更多的工作细节,比如该以什么样的顺序标记/复制对象?实现的性能如何?

Cheney在1970年提出的复制算法是最经典的算法,JVM中串行回收就是Cheney算法的变异实现(将新生代分为3个分区,且涉及对象晋升)。下面来演示一下串行回收中的复制算法。

假设初始状态如图3-12所示,对象都分配在Eden中,且因Mutator无法成功在Eden空间分配对象,触发了垃圾回收。为了演示简单,这里只画出了Eden和To空间,省略了From空间。

图3-12 堆空间初始状态

从根集合出发开始标记Eden空间中的活跃对象并将活跃对象复制到To空间中。这里假设只存在一个根,并且引用到对象A。根(Root)在Eden引用对象A,说明对象A活跃,将对象A复制到To空间的A'。A'和A有完全相同的数据,所以A'中的字段仍然指向Eden空间中的对象(A'和A相同的字段指向的对象也是完全相同的)。对象A被复制以后堆空间状态如图3-13所示,用虚线表示正在处理的对象。为了清晰地描述复制的过程,使用不同的颜色描述对象复制的状态,黑色表示对象已经处理完成,灰色表示对象正在处理,白色表示对象尚未被处理。

在To空间中有两个指针Scan和Free。其中Free表示To空间中后面的内存尚未使用,Scan表示To空间中标记/复制的对象位置。这两个指针用于模拟一个队列(queue),Scan指向队列头,Free指向队列尾。当A复制到To空间的A'后,To空间的Free指针随之增长,并且对象A'应该标记为灰色,表示待复制A'的成员变量。

图3-13 对象A复制以后的堆空间状态

当A被复制到To空间之后,需要把A'成员变量指向Eden空间中的活跃对象也复制到To空间中。在图3-13中,A'存在两个字段,分别指向B和D。A'中存在两个对象,在实现时应先处理哪一个对象?在JVM中使用一个oopmap来标记对象A'的内存布局,其中对象B和D在对象A'中的相对偏移位置都是固定的,假设A'中内存布局指向对象B的字段在前,指向对象D的字段在后。处理对象A'时,当从前向后处理字段时就会先处理对象B,当从后向前处理时就会先处理对象D(在JVM中存在两种顺序的处理方法)。通常是从前向后处理字段,这里也假设字段B先被处理。所以对象B将从Eden复制一份到To空间中,名字为B',同时To空间中的Free指针也随之增长,B'也被标记为灰色。堆空间状态如图3-14所示。

图3-14 对象B复制以后堆空间的状态

对象B被复制完成后,继续处理A'中的下一个引用对象D,同样D也被复制到To空间中,名字为D'。

当对象D'被复制到To空间后,对象A'的所有成员变量都已经复制完成,所以颜色变成黑色。此时堆空间状态如图3-15所示。

图3-15 对象A完成复制后堆空间状态

还有一种情况,假设对象A'还有一个字段指向老生代中的对象F,对象F在A'遍历时该如何处理?简单的回答就是不做任何处理,因为对象F的位置不会发生变化,所以不需要任何额外处理。

由于对象A'的颜色变成黑色,意味着可以处理下一个对象B'。那么怎么知道该处理B'呢?这就要用到上面提到的Scan指针,当A'被处理完成后,Scan指针将向后移动,此时Scan指向的对象就是B'。按照同样的方法来处理对象B'。堆空间状态示意图如图3-16所示。

图3-16 移动Scan指针处理下一个对象

当B'被处理完成后也将变成黑色,同时Scan继续向后移动。此时Scan指向对象D',所以开始标记/复制对象D'中的字段。D'中存在一个引用字段指向对象E,E也被复制到To空间中,名字为E'。同时To空间中的Free指针也随之增长,E'也被标记为灰色。堆空间状态如图3-17所示。

图3-17 复制对象E后堆状态示意图

同样地D'被处理完成,颜色变成黑色。继续处理E'。堆状态示意图如图3-18所示。

图3-18 对象D处理完成后堆状态示意图

因为E'不存在引用字段,所以不需要继续复制任何对象到To空间。此时Scan指针和Free指针重合,表示待标记/复制的对象全部完成,如图3-19所示。

图3-19 对象全部复制完成后堆状态示意图

此时所有活跃对象都从Eden空间复制到To空间中,Eden空间就可以被再次用于Mutator分配对象,所以Eden看起来就像被清空了一样,如图3-20所示。实际上为了确保效率,Eden空间不做任何额外的处理,新分配的对象直接覆盖原来的内存数据。

图3-20 重用Eden空间示意图

Cheney的复制算法实际上是一个宽度优先的遍历算法,该算法虽然使用了宽度优先,但并未真正消耗额外的空间,而是直接借助了To空间模拟了一个队列。所以这个算法非常适用于内存配置不高的场景,这也是串行回收中选择该算法的主要原因。

需要指出的是,JVM中除了串行回收之外,其他的垃圾回收器都未直接采用Cheney的复制算法,而是进行变形,引入了一个额外的标记栈辅助对象的标记过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值