java垃圾回收(二)——垃圾回收算法
在JVM规范中,并没有明确指明GC的运作方式,各个厂商可以采用不同的方式去实现垃圾收集器。这篇文章简单介绍常见的垃圾回收算法。
标记-清除算法
标记-清除算法分两个步骤,分别为“标记”和“清除”,字如其人。它是一个最基础的垃圾回收算法,更高级的垃圾回收算法都是基于它改进的。
它的运行过程是这样的:首先标记出所有需要回收的对象,标记完成后,再统一回收掉所有被标记的对象。
标记清除.png标记-清除算法的缺点有两个,一个是空间问题,标记清除之后会产生大量的不连续内存碎片。内存碎片太多,程序在之后的运行过程中就有可能找不到足够的连续内存来分配较大的对象,进而不得不提前触发另一次垃圾回收,导致程序效率降低。标记-清除算法的另一个缺点是效率问题,标记和清除的效率都不高,两次扫描耗时严重。
复制算法
复制算法把内存按容量划分为大小相等的两块,每次只使用其中的一块。如果正在用的这块没有足够的可使用空间了,那么就将还活着的对象复制到另一块去,再把使用过的内存一次性清掉。
复制算法.png这样就实现了简单高效的做法,每一次进行内存回收时,就不用再去考虑内存碎片这些复杂的情况,只需要移动堆顶指针就可以。但是缺点也很明显,可使用内存只有原来的一半了,而且持续复制生命力很旺盛的对象也会让效率降低哇。复制算法适用于存活对象少、垃圾对象多的情况,这种情况在新生代比较常见。
标记-压缩算法
在老年代,大部分对象都是存活的对象,复制算法在这里就不靠谱了,所以有人提出了标记压缩算法,标记过程和标记清除算法一样,但是清理时不是简单的清理,而是让所有存活的对象都向一端移动,然后直接清理掉边界以外的内存,需要移动对象的成本。
标记压缩.png分代算法
前面的几种垃圾回收算法中,没有一种可以完全替代其他算法,他们具备各自的特点与优势,因此更好的方法是根据垃圾对象的特性来选择合适的回收算法。
分代算法的思想就是将内存空间根据对象的特点不同进行划分,选择合适的垃圾回收算法来提高回收效率。分代的思想已经被现有的虚拟机广泛采用。
分区算法
分区算法就是将整个堆空间再划分为连续的不同小区间,每一个小区间独立使用,也独立回收。
分区算法.png一般在相同条件下,堆空间越大,那么一次GC的时间就越长,因此而产生的停顿时间也就越长。为了控制GC的停顿时间,根据目标停顿时间,每次合理回收若干个小区间,而不是整个堆空间,进而减少一个GC的停顿时间。