怎么判断对象存活

73 阅读1分钟

在 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回收 --> 加入队列[引用对象加入队列]
    应用线程 --> 轮询队列[处理队列中的引用]

并发扫码带来的问题:无法判断对象到底是存活还是死亡