垃圾收集器2:收集算法
主要通过阅读《深入了解Java虚拟机》(周志明 著)和网络资源汇集而成,为本人学习JVM的笔记。同时,本文理论基于JDK 1.7版本,暂不考虑 1.8和1.9 的新特性,但可能初略提到。
垃圾收集算法主要有以下几种: 标记-清除算法(Mark-Sweep)、复制算法(Copying) 和 标记-整理算法(Mark-Compact)。
标记-清除算法(Mark-Sweep)
首先标记出所有需要回收的对象,标记完成后统一回收所有被标记对象。
主要不足之处:
- 效率问题
标记和清除两个过程的效率都不高。正如上篇笔记所记,GC会从 GC Roots 开始遍历标记,然后从 Java 堆从头到尾遍历清除垃圾。 - 空间问题
会产生大量不连续的空间,所以无法分配大对象,最终因为空间问题不得不提前触发 GC 动作。
复制算法(Copying)
复制算法是为了解决标记-清除算法的效率问题。
将可用内存的容量分为大小相等的两块,每次只使用其中的一块,当这一块内存使用完了,就把存活着的对象复制到另外一块上面,然后再把已使用过的内存空间清理掉。但是,这种做法的代价是将内存缩小为原来的一半。
关于该算法的商业应用:
1. 目的:利用这种算法来回收新生代。
2. 方案:将内存分为 Eden 与 Survivor(有2块) 空间,比例一般为 8:1:1。每次回收将存活对象复制到一块 Survivor 空间,其他空间全部回收。
3. 空间保证(分配担保机制):因为无法保证回收存活对象的内存大小,只能依赖其他内存(指老年代)进行分配担保。
4. 代价:每次回收只有一块 Survivor 空间(10%内存)被浪费。
标记-整理算法(Mark-Compact)
在标记后不是对未标记的内存区域进行清理,二是让所有的存活对象都向一端移动,然后清理掉边界外的内存。该方法主要用于老年代。
分代收集算法
将Java堆分为几个空间:
- 新生代
- 特点:大批对象死去,只有少量存活。
- 算法:复制算法。
- 老年代
- 特点:对象存活率高,没有额外空间进行分配担保。
- 算法:标记-清除算法/标记-整理算法。