标记-清除算法不用更新引用,因其不移动对象,存活对象物理地址不变,gc roots仍可通过原路径访问,无悬垂指针风险;仅标记和清除两阶段,依赖stw保障一致性,无需地址映射或转发指针。

标记-清除算法本身不涉及对象移动,因此不需要更新引用。这是它与标记-整理、复制算法最根本的区别——没有地址变更,自然无需修正指针。
为什么标记-清除不用更新引用?
因为它的清除阶段只是“逻辑上回收”内存块,不改变存活对象的物理位置。所有被标记的对象原地保留,它们内部字段、栈中变量、静态引用所指向的地址完全不变。GC Roots 仍能通过原有路径访问到这些对象,程序运行时不会出现悬垂指针或访问错误。
哪些场景才需要引用更新?
只有当 GC 算法导致对象内存地址发生变化时,才必须同步更新所有指向它的引用。典型情况包括:
- 标记-整理算法:存活对象被统一滑动到堆的一端,地址批量重映射,必须遍历栈、静态区、对象字段三类引用源,用预计算的新地址替换旧值
- 复制算法(如新生代Minor GC):存活对象从 Eden 或 Survivor 区复制到另一块区域,引用需指向新副本地址;JVM 在复制过程中直接更新相关指针
- 压缩式回收(如ZGC、Shenandoah的部分阶段):虽支持并发,但仍需在迁移前后协调引用更新,常借助读屏障+转发指针机制实现原子切换
标记-清除的数据同步特点
它只做两件事:标记可达性、释放不可达内存。整个过程的数据一致性靠Stop-The-World(STW)保障——暂停所有用户线程,确保标记阶段看到的引用图是静态快照,清除阶段不会遇到正在修改对象字段或压栈/出栈的竞态操作。不需要额外的数据同步机制,也不维护地址映射表或转发指针。
一个常见误解澄清
有人误以为“清除后腾出空闲块,分配新对象时要更新引用”,其实不然。新对象分配是独立于 GC 的内存管理行为,由分配器(如 bump-the-pointer 或 freelist)决定起始地址,与旧对象的引用无关。只要存活对象地址没变,它们的字段值、引用关系就保持有效,无需任何同步动作。











