Jvm垃圾对象的判定标准
JVM 判定垃圾对象的标准主要基于可达性分析(Reachability Analysis)算法,而不是简单的引用计数。这一算法的核心思想是,从一系列被称为“GC Roots”(垃圾回收根对象)的起点出发,遍历所有可达的对象。如果一个对象无法通过任何引用链从 GC Roots 访问到,那么它就被判定为是垃圾对象,可以被垃圾回收器回收。
以下是 JVM 判定垃圾对象的详细标准:
-
可达性分析算法(Reachability Analysis)
- 现代 JVM 普遍采用可达性分析来判断对象是否存活。该算法通过将内存中的所有对象看作一个图,从 GC Roots 作为起始点,沿着引用链向下搜索。所有能被搜索到的对象都被认为是“可达的”(即存活对象),而那些没有被搜索到的对象则被认为是“不可达的”(即垃圾对象)。
- 相较于引用计数法,可达性分析算法能够有效解决对象之间循环引用导致无法回收的问题。
-
GC Roots(垃圾回收根对象) GC Roots 是垃圾回收器进行可达性分析的起始点。它们是 JVM 中一些特殊的引用,总是被认为是“活跃的”或“可达的”,因此它们以及它们直接或间接引用的对象都不会被垃圾回收。常见的 GC Roots 类型包括:
- 虚拟机栈(VM Stack)中引用的对象:每个线程在执行方法时都有一个栈帧,栈帧中的局部变量表、方法参数、返回值等如果引用了堆中的对象,这些引用就作为 GC Root.
- 本地方法栈(Native Method Stack)中 JNI (Java Native Interface) 引用的对象:通过 JNI 调用本地方法时,本地方法栈中可能保存着对 Java 对象的引用.
- 方法区(Method Area)中类静态属性引用的对象:类的静态变量属于类本身,只要类被加载且未被卸载,静态字段引用的对象就保持可达.
- 方法区中常量引用的对象:例如字符串常量池中的引用.
- 所有被同步锁(
synchronized关键字)持有的对象:正在被用作同步监视器的对象. - 活跃线程(Active Threads):正在运行的线程对象本身及其线程本地变量.
- 系统类加载器加载的类:如 Java 标准库中的类.
- JVM 内部的一些对象:为了 JVM 自身的目的而持有的对象,具体取决于 JVM 的实现.
-
标记-清除(Mark-and-Sweep)过程 垃圾回收器通常采用“标记-清除”算法来回收内存。这个过程分为两步:
- 标记阶段(Mark Phase):垃圾回收器从 GC Roots 开始遍历所有可达对象,并将其标记为“存活”.
- 清除阶段(Sweep Phase):遍历整个堆内存,回收所有未被标记为“存活”的对象,释放其占用的内存空间.
-
引用类型 Java 中定义了四种引用强度,它们对对象的垃圾回收行为有不同影响:
- 强引用(Strong Reference):最常见的引用类型。只要存在强引用,垃圾回收器永远不会回收被引用的对象。当内存不足时,JVM 宁愿抛出
OutOfMemoryError也不会回收具有强引用的对象. - 软引用(Soft Reference):用于描述一些还有用但并非必需的对象。只被软引用引用的对象,在 JVM 内存不足时会被回收.
- 弱引用(Weak Reference):用于描述非必需对象。只被弱引用引用的对象,在垃圾回收器扫描到它时,无论当前内存是否充足,都会被回收.
- 虚引用(Phantom Reference):是最弱的一种引用,它的存在不会对对象的生命周期构成任何影响。主要用于跟踪对象被垃圾回收的状态,配合引用队列使用.
- 强引用(Strong Reference):最常见的引用类型。只要存在强引用,垃圾回收器永远不会回收被引用的对象。当内存不足时,JVM 宁愿抛出