JVM 使用可达性分析算法来判断对象是否已经死亡(即不再被使用)。该算法通过确定对象是否可以从根对象(如全局变量、活跃线程的栈中的变量等)访问到来判断其是否存活。如果一个对象无法通过任何引用链从根对象访问到,那么它被认为是“不可达”的,即可以被回收。
可达性分析算法的基本过程
-
根搜索(Root Searching):
- 算法从一组称为“根”的对象开始,这些根对象包括:
- 全局变量(如静态变量)
- 活跃线程的栈中的局部变量(如方法参数、局部变量等)
- JNI 引用(Java Native Interface 引用)
- 方法区中的常量引用(如字符串常量池中的引用)
- 这些根对象被认为是程序中正在使用的对象,因此它们是可达的。
- 算法从一组称为“根”的对象开始,这些根对象包括:
-
遍历对象图(Object Graph Traversal):
- 从根对象开始,算法递归地遍历对象之间的引用关系。
- 如果一个对象引用了另一个对象,那么被引用的对象也会被视为可达的。
- 算法会持续遍历并标记所有可以被访问到的对象,直到无法再找到新的可达对象为止。
-
标记阶段(Marking Phase):
- 在遍历过程中,已经被访问过的对象将被标记为“被访问过”,以避免重复访问同一个对象。
- 标记的目的是区分哪些对象是可达的,哪些是不可达的。
-
清除阶段(Sweeping Phase):
- 在标记阶段完成后,所有未被标记为“被访问过”的对象将被认为是“不可达”的,即垃圾对象。
- 这些垃圾对象占用的内存将被释放,并标记为可用内存。
总结
- 可达性分析算法通过从根对象开始遍历对象图,标记所有可达的对象。
- 未被标记的对象被认为是“不可达”的,即垃圾对象,可以被回收。
- 该算法的核心思想是:如果一个对象无法通过任何引用链从根对象访问到,那么它就是不可达的,可以被回收。
去重
在遍历对象图的过程中,为了避免重复访问同一个对象,算法会使用标记机制来记录哪些对象已经被访问过。这样可以确保每个对象只被访问一次,提高算法的效率。
示例
假设有以下对象引用关系:
根对象 -> A -> B -> C
A -> D
B -> E
- 从根对象开始,算法首先访问对象 A,并标记 A 为可达。
- 接着,算法访问 A 引用的对象 B 和 D,并标记它们为可达。
- 然后,算法访问 B 引用的对象 C 和 E,并标记它们为可达。
- 最终,所有被标记的对象(A、B、C、D、E)都是可达的,而未被标记的对象则是不可达的,可以被回收。
通过这种方式,可达性分析算法能够有效地判断哪些对象是存活的,哪些是可以被回收的。