jvm垃圾回收只保障内存逻辑安全而非业务数据一致性;gc roots精确枚举依赖可快照区域与oopmap;根节点枚举和标记阶段必须stw以构建一致性快照;并发收集靠写屏障维持三色标记安全;移动式回收需oopmap与安全点原子更新引用。

JVM 垃圾回收不保证业务数据一致性,只保障内存层面的逻辑安全——即不误删存活对象、不访问已释放地址。这种“一致性”是内存管理的正确性,不是数据库事务那种 ACID 一致性。
GC Roots 精确枚举是安全起点
HotSpot 将 GC Roots 严格限定在几个可快照区域:Java 栈帧里的局部变量、类的静态字段、常量池引用、JNI 全局引用、被 synchronized 锁住的对象等。这些位置不会在线程运行中动态增删,能被一次性准确抓取。
- 若枚举遗漏(比如某个 JNI 引用未纳入),会导致存活对象被错误回收,引发悬垂指针和崩溃——这是实现缺陷,不是算法本身问题
- OopMap 结构提前记录了栈上引用的具体偏移位置,避免全栈扫描,大幅缩短枚举耗时
- 根节点枚举必须 STW,否则线程修改栈内容会导致快照失真
STW 构建一致性快照
标记阶段强制暂停所有 Java 线程(Stop-the-World),确保从 GC Roots 出发的整个引用图在分析过程中静止不变。
- 例如,某线程正执行
obj.field = null,如果标记发生在赋值前,obj 仍被引用;发生在赋值后,obj 可能被回收。STW 消除了这种竞态 - 这个快照是可达性分析可预测、可验证的基础,也是 STW 最核心的不可替代作用
并发收集靠写屏障维持三色标记安全
CMS、G1 等允许用户线程与标记线程并发,但需额外机制防止漏标或错标:
- 写屏障在引用字段更新时插入钩子,捕获变动并通知标记线程
- G1 使用 SATB(Snapshot-At-The-Beginning):标记开始时拍下快照,后续新增引用暂不处理,旧引用断开则加入灰色队列重新扫描
- CMS 使用增量更新(Incremental Update):在引用被修改时,把被修改对象重新标记为灰色,确保其子节点也被检查
移动式回收依赖 OopMap 与安全点原子更新引用
像 Serial、Parallel、ZGC 的部分阶段会移动对象,此时所有指向该对象的引用都必须同步更新,否则变成野指针。
- OopMap 提前标明哪些栈/寄存器位置存着对象引用,GC 移动对象后能精准定位并修正这些引用
- 引用更新必须在安全点(Safepoint)进行,此时所有线程已到达可控状态,更新操作可原子完成
- 移动过程本身不涉及业务逻辑,只改指针值,因此不破坏业务一致性,但要求 JVM 层引用关系绝对准确











