算法原理
复制算法首先将或者的内存空间分为2块,每次只使用其中一块,在垃圾会搜时将正在使用的内存中的存活对象复
制到未被使用的内存块中,之后清楚正在使用的内存块中的所有对象,交换2个内存的角色,最后完成垃圾回收。
image
年轻代中的GC
HotSpot JVM
把年轻代分为了三部分:1个Eden区
和2个Survivor区
(分别叫from
和to
)。默认比例为8:1,为啥默认会是这个比例,接下来我们会聊到。一般情况下,新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC
后,如果仍然存活,将会被移到Survivor区
。对象在Survivor区
中每熬过一次Minor GC
,年龄就会增加1岁,当它的年龄增加到一定程度时,就会被移动到年老代中。
因为年轻代中的对象基本都是朝生夕死的(80%以上),所以在年轻代的垃圾回收算法使用的是复制算法,复制算法的基本思想就是将内存分为两块,每次只用其中一块,当这一块内存用完,就将还活着的对象复制到另外一块上面。复制算法不会产生内存碎片。
在GC
开始的时候,对象只会存在于Eden区
和名为“From”的Survivor区
,Survivor区
“To”是空的。紧接着进行GC
,Eden区
中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold
来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。经过这次GC
后,Eden区
和From区
已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区
域是空的。Minor GC
会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。
存在问题
由于JVM中的绝大多数对象都是瞬时状态的,生命周期非常短暂,所以复制算法被广泛应用于年轻代中。分区、复制的思路不仅大幅提升了垃圾回收的效率,而且也将原本复杂的内存分配算法变的前所未有的简明扼要(既然每次内存回收都是对整个半区空间的回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存就可以了)。
不过在垃圾收集技术中,复制算法提高效率的代价是认为的将可用内存缩小了一半。
网友评论