垃圾回收的过程主要包括两部分:找出已死去的对象、移除已死去的对象。
确定哪些对象存活有两种方式:引用计数算法、可达性分析算法。
方案一:引用计数算法
给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值加1;当引用失效时,计数器值减1;计数器的值为0时即表明对象已经死去(可被回收)。
优点:实现简单,判定效率高。
缺点:难解决对象之间互相引用的问题。
如:对象objA和objB都有字段instance,令objA.instance=objB,objB.instance=objA;除此之外,objA和objB再无其他引用,理论上objA和objB可以被回收(无法被访问),但因为计数器变为0,所以导致内存泄露。
方案二:可达性分析算法
通过“GC Roots”对象作为起始点,从这些节点开始向下搜索,被搜索到的对象marked,堆中未被maked的对象表明不可达(可被回收)。
在Java语言中,课作为GC Roots的对象包括如下四种:
1.虚拟机栈(栈帧中的本地变量表)中引用的对象
2.方法区中类静态属性引用的对象
3.方法区中常量引用的对象
4.本地方法栈中JNI(即一般说的Native方法)引用的对象
垃圾收集算法:
1.标记-清除(Mark-Sweep):用上面描述的方法标记出需要回收的对象,标记后统一回收所有被标记的对象。
2. 复制算法: 为了解决上述算法清除造成可用空间碎片化的问题,复制算法将内存空间分成大小相等的两部分,当一部分使用完时,将存活的对象移至另一部分。
3. 标记-整理(Mark-Compact):上述算法造成实际使用空间只占了分配空间的一半,标记-整理算法在标记后,将所有存活对象向一端移动,然后直接清理掉端边界以外的内存。
4.分代收集算法:研究表明新生代中的对象98%是“朝生夕死”的,所以将对象添加年龄属性,根据不同的年龄决定对象存放位置。具体可参考:Java垃圾回收
说明:本文的内容参考书籍《深入理解Java虚拟机(第2版)》