# 垃圾回收算法 Uncompleted
垃圾回收(Garbage Collection)是一种自动的内存管理机制。当动态内存不再需要时,就应当予以释放,以让出内存,这就是垃圾回收。
垃圾回收算法的优缺点主要看以下几个方面:
- 吞吐量
- 最大暂停时间
- 堆使用效率
- 访问的局部性
# 引用计数算法 Reference Counting
记录每个对象被引用的次数。每次新建对象、赋值引用和删除引用的同时都要更新计数器,如果计数器的值为0就直接回收内存。
给对象中添加一个引用计数器,每当有一个地方引用它时,计数器的值就加1;当引用失效时,计数器的值就减1。当计数器的值为0时,这个对象就是不可再被使用的。
主流Java虚拟机里并没有选择引用计数法来管理内存,主要原因是「它很难解决对象之间互相循环引用的问题」。
/**
* 因为objA.instance = objB, objB.instance = objA;
* 之后令objA = null, objB = null,这两个对象就不可能再被访问了
* 但因为它们互相引用着对方,导致引用计数都不为0,导致无法通知GC收集器回收它们
*/
public static void testGC() {
ReferenceCountingGC objA = new ReferenceCountingGC();
ReferenceCountingGC objB = new ReferenceCountingGC();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
System.gc();
}
# 可达性分析算法 Reachability Analysis
这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径被称为引用链(Reference Chain),当一个对象到达GC Roots时都没有任何引用链与其相连时,就证明该对象是不可用的,将会被判定是可回收的对象。
# 标记-清除算法 Mark-Sweep GC
首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。
- 标记阶段:从根集合出发,将所有的活动对象及其子对象打上标记
- 清除阶段:遍历堆,将所有的非活动对象(未打上标记的对象)连接到空闲链表上
不足之处:
- 效率问题:标记和清除的两个过程效率都不高
- 空间问题:标记清除之后会产生大量的不连续的内存碎片,空间碎片太多就会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
# 标记-压缩(整理)算法 Mark-Compact GC
后续步骤不是直接对可回收的对象进行清理,而是让所有存活的对象都向一端移动,即将所有的活动对象紧密地排在堆的一端(压缩),然后直接清理掉端边界以外的内存,消除了内存碎片,但压缩需要成本。
# 复制算法 Copying
将堆分为两个大小相等的From和To两块,每次只使用其中的一块。利用From空间进行分配,当From空间满了,就将其中的活动对象复制到To空间,之后将两个空间互换即完成GC。
每次都是对整个半区进行内存回收,分配内存时也就不用考虑内存碎片等复杂情况。
但这种算法的代价是将内存缩小到了原来的一半,因为分成了两块相等的内存空间。
← HotSpot虚拟机对象 垃圾收集器 →