判断垃圾
计数引用
在对象中添加一个引用计数器,如果被引用计数器加 1,引用失效时计数器减 1,如果计数器为 0 则被标记为垃圾。简单高效,但在 Java 中很少使用,因为存在对象循环引用的问题,导致计数器无法清零。
可达性分析
通过一系列称为 GC Roots 的根对象作为起始节点集,从这些节点开始根据引用关系向下搜索,搜索过程走过的路径称为引用链,如果某个对象到 GC Roots 没有任何引用链相连则会被标记为垃圾。可作为 GC Roots 的对象包括:虚拟机栈和本地方法栈中引用的对象、类静态属性引用的对象、常量引用的对象。
GC 算法
标记清除
分为标记和清除阶段,首先从每个 GC Roots 出发依次标记有引用关系的对象,最后清除没有标记的对象。如果堆包含大量对象且大部分需要回收,必须进行大量标记清除,效率低。
存在内存空间碎片化问题,分配大对象时容易触发 Full GC。
标记整理
老年代使用标记整理算法,标记过程与标记清除算法一样,但不直接清理可回收对象,而是让所有存活对象都向内存空间一端移动,然后清理掉边界以外的内存。
标记复制
为解决内存碎片,将可用内存按容量划分为大小相等的两块,每次只使用其中一块,主要用于新生代。对象存活率高时要进行较多复制操作,效率低。如果不想浪费空间就需要有额外空间分配担保,老年代一般不使用此算法。