之前的一篇:JVM垃圾回收前奏-对象已死?介绍了JVM会回收掉什么样的对象,那在明确了需要回收的对象之后,JVM会如何回收掉这些对象了?首先需要了解现在主流的一些垃圾回收算法垃圾回收算法。
1. 标记-清除算法
标记-清除算法会将整个回收过程分成“标记”和“清除”两个阶段。首先通过可达性分析标记出需要回收的对象,然后在清除阶段清除所有未被标记的对象。
整个算法其实带来了两个缺点:第一个是回收效率不高,第二个是容易引起大量的不连续的内存碎片。如果太多的内存碎片,可能会导致需要分配一个大的对象时无法申请到足够的内存空间,那这时会提前触发新一轮的垃圾回收,这必然会影响系统的性能。
2. 复制算法
复制算法的思想是:将整个内存空间分成两块,每次只使用其中的一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,之后清除掉正在使用的这一块的所有内存空间,然后交换两个内存的角色,完成垃圾回收。这样每次使用只使用一块内存,指针的移动也是移动栈顶指针就行。整个算法的优点在于:实现简单、运行高效,而缺点在于:内存使用率不高。
一般工业上使用复制算法并不是将内存空间分成完全对等的两块内存,例如:HotSpot虚拟机的新生代空间的回收就是使用复制算法完成,但是它是将整个内存空间分成3个区域,一个Eden分区,一个from survivor分区和一个to survivor分区,Eden 分区和Survivor分区的大小比例默认是8:1,但是你可以通过参数指定。为什么针对新生代需要这样来划分内存空间呢?因为,研究表明,新生代的对象生命周期大都是非常短暂(应该是>90%以上的对象),可以说是朝生夕死,所以这样划分很合理。
3. 标记-压缩算法
标记-压缩算法也被称为标记-整理算法。它也是先通过标记出哪些对象需要回收,但是标记完后它并不是立即回收掉这些对象,而是将那些存活的对象移动到内存的一端,然后直接整个清理掉边界以外的内存。这种方法既避免了碎片的产生,又不需要两块相同的内存空间,因此,其性价比比较高。(根据老年代的特别,一般回收老年代会使用标记-压缩算法)
4. 分代收集算法
由于内存区域的对象存活时间都是不一样的,很难用一种垃圾回收算法来完美的解决整个内存空间的回收,所以,当前大部分的商业虚拟机都是采用“分代收集”算法。这种算法的思想是,根据对象存活的周期不同将内存划分成几块,一般是新生代和老年代两块。由于新生代中对象朝生夕死,只有少量的对象存活,那就选用复制算法,只需要付出少量存活对象的赋值成本就可以完成收集。而老年代中因为对象存活率高,没有额外的空间进行分配担保,一般使用“”标记-清理“ 或者”标记-整理“算法来回收。
图片来自网络
网友评论