在之前Java 运行期数据区一文中,介绍了运行时内存的各个部分。其中程序计数器、虚拟机栈、本地方法栈都随线程消亡,所以,这几个区域的内存分配和回收都具备确定性。而 Java 堆和方法区不同,我们只有在程序运行期间才能知道会创建哪些对象,这部分的内存分配和回收都是动态的,这也正是垃圾回收器关注的部分。
对象的生与死
垃圾回收器要在进行回收前,需要确定哪些对象的状态,是“存活”还是”死亡“。
引用计数法
给对象添加一个引用计数,每当有一个地方引用对象时,引用计数加 1 ;当引用实现时,引用计数减 1 ;引用计数位 0 的对象不能再背引用。
C++ 中的 unique_ptr
内部就是通过引用计数来实现的,不过该方法有个弊端,对象间可能存在循环引用。Java 没有采取改方法。
可达性分析(Reachability Analysis)算法
Java、C# 都通过该方法来判定对象是否存活。可达性分析算法的思路是通过一系列称为“GC Roots”的对象作为起始点,从这些点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到 GC Roots 没有任何引用相连(从 GC Roots 到这个对象不可达)时,则证明这个对象是不可用的。
在 Java 中,以下几种对象可以作为 GC Roots :
- 虚拟机栈(栈帧中的本地变量表)中引用的对象;
- 方法区中类静态属性引用的对象;
- 方法区中常量引用的对象;
- 本地方法栈中 JNI(Native 方法) 引用的对象。