在 JVM 内存回收前,判断对象存活是垃圾回收的核心前提。以下是完整的存活判定机制及技术实现:
一、存活判定核心算法
graph TD
A[对象存活判定] --> B[引用计数法]
A --> C[可达性分析法]
B --> B1[简单高效]
B --> B2[循环引用问题]
C --> C1[Java实际采用]
C --> C2[GC Roots溯源]
1. 可达性分析算法(Java 实际使用)
flowchart LR
GC_Roots[GC Roots] -->|引用链| ObjectA
GC_Roots -->|引用链| ObjectB
ObjectA --> ObjectC
ObjectB --> ObjectC
未连接 --> ObjectD
未连接 --> ObjectE
存活判定:
- 从 GC Roots 出发,通过引用链可达 → 存活
- 无引用链连接 → 可回收
二、GC Roots 的四大类型
1. 根对象来源
classDiagram
class GCRoots {
+虚拟机栈引用的对象
+方法区静态属性引用的对象
+方法区常量引用的对象
+本地方法栈JNI引用的对象
+同步锁持有的对象
+JMXBean等系统对象
}
2. 具体示例
| GC Roots 类型 | 具体示例 |
|---|---|
| 虚拟机栈引用 | 方法中的局部变量:User user = new User() |
| 静态属性引用 | public static Config config = new Config() |
| 常量引用 | public static final Logger LOG = LogManager.getLogger() |
| JNI 引用 | JNIEnv->FindClass("java/lang/String") |
三、对象存活判定流程
1. 完整判定流程
sequenceDiagram
participant GC
participant Heap
participant Finalizer
GC->>Heap: 扫描GC Roots
Heap-->>GC: 返回初始存活集
GC->>Heap: 递归标记可达对象
Heap-->>GC: 返回完整存活集
GC->>Finalizer: 检查finalize队列
Finalizer-->>GC: 返回待处理对象
GC->>Heap: 二次标记
2. 两次标记与 finalize()
graph TD
首次标记 --> 筛选[筛选需finalize对象]
筛选 --> 队列[加入F-Queue]
队列 --> 执行[Finalizer线程执行finalize]
执行 --> 复活[对象可能被复活]
复活 --> 移除[移出回收集]
执行 --> 未复活
未复活 --> 二次标记
二次标记 --> 回收
四、四种引用类型与回收策略
1. 引用强度与回收关系
graph LR
强引用[Strong Reference] --> 永不回收
软引用[Soft Reference] --> 内存不足时回收
弱引用[Weak Reference] --> 下次GC回收
虚引用[Phantom Reference] --> 随时回收
2. 引用队列机制
flowchart TD
创建引用 --> 关联队列[关联ReferenceQueue]
GC回收 --> 加入队列[引用对象加入队列]
应用线程 --> 轮询队列[处理队列中的引用]