深入理解Java虚拟机(四)——垃圾收集策略(2)

240 阅读3分钟

垃圾收集算法

1. 标记-清除算法

1.1 标记-清除算法的理解

标记-清除算法分为“标记”和“清除”两部分,“标记”算法在上一篇博文 深入理解Java虚拟机(三)——垃圾收集策略 (1) 里已做了介绍,“清除”即回收被标记的对象。

1.2 标记-清除算法的特点

●是最基础的收集算法。后续的收集算法都是基于这种思路并针对其不足进行改进而得到的。

●标记和清除的效率不高。

●标记清除后会产生大量的内存碎片,当需要为对象分配较大内存时,可能因无法划分出足够的空间而不得不提前触发一次垃圾收集动作。

2. 复制算法

2.1 复制算法的理解

一块内存被平分为两块大小一致的内存区域,当其中一块内存发生垃圾收集动作时,存活下来的对象将被复制到另外一块内存中,执行完这步操作后,原来的那块内存空间将被全部释放。

2.2 复制算法的特点

●垃圾收集后产生的内存碎片问题得以解决。

●每次只能使用一半内存,另外一半内存被“浪费”掉了,代价太高。

2.3 复制算法的应用

现在的商业虚拟机采用复制算法来回收新生代,内存被划分为一块较大Eden区、两块较小Survivor区,他们的默认内存大小比例为8:1:1。垃圾收集动作发生后,Eden区和一块Survivor区存活下来的对象将复制存放到另一块survivor区,原来的Eden区和Survivor区都将全部释放。

2.4 分配担保

2.3小节的复制算法存在一个问题:当Survivor区不够用该怎么办呢?解决办法就是寻求其他内存区域(老年代)存放对象,这就是分配担保。

3. 标记-整理算法

3.1 标记-真理算法出现的背景

复制收集算法在对象存活率较高时要进行较多的复制操作,导致效率降低。此外,新生代采用复制算法,当内存不够时还能找老年代进行分配担保,若是老年代也采用复制算法,将不会有另外的内存进行分配担保。因此老年代不采用复制收集算法。为了解决老年代垃圾收集的问题,于是提出了标记-整理算法。

3.2 标记-整理算法的理解

标记-整理算法同样分为两部分:“标记”和“整理”。“标记”和标记-清除算法里的“标记”是一样的,“整理”即把存活下来的对象都往一端移动,最后把界限处之后的内存区域全部释放。

4. 分代收集算法

虚拟机把堆内存划分为新生代和老年代。新时代的对象存活率低,采用复制算法只需复制小部分对象即可实现垃圾收集,效率较高;老年代的对象存活率高,并且没有空间对它进行分配担保,因此不宜采用复制算法进行垃圾收集,而应采用标记-清除或是标记-整理算法。

5. Stop The World

垃圾收集动作发生时,所有Java线程都必须暂停运行(官方称之为Stop The World)。若不暂停所有线程就进行垃圾收集,则对象的引用关系仍然在不断变化着,这将导致通过可达性算法分析出的引用链无法保证准确性。