jvm对象回收是分阶段闭环流程:先用可达性分析(以gc roots为起点)判定不可达对象,再经标记、回收(新生代复制/老年代标记整理)、特殊引用处理三阶段完成;仅堆和元空间需gc,栈与程序计数器随线程自动释放。

JVM 对象内存回收不是简单“删掉就完事”,而是一套分阶段、有策略、带容错的闭环流程。核心围绕“哪些对象该回收”和“怎么安全高效地回收”两个问题展开,涉及判定、标记、清理、整理、特殊处理等多个环节。
如何判断一个对象该被回收
现代 JVM 全部采用可达性分析算法,不再使用有循环引用缺陷的引用计数法。
- 从一组称为GC Roots的对象出发(如虚拟机栈中的局部变量、方法区的静态变量、常量池引用、JNI 引用等),沿着所有引用链向下搜索
- 任何无法从 GC Roots 到达的对象,即被判定为“不可达”,进入待回收候选队列
- 注意:不可达不等于立即死亡。若对象重写了
finalize()方法且尚未执行过,会被放入 F-Queue 队列,由 Finalizer 线程尝试调用一次——这是它唯一一次“自救”机会;若在finalize()中重新与 GC Roots 建立强引用(比如赋值给 static 字段),对象就能复活 - 但
finalize()已被标记为废弃,不推荐使用,既不可靠又影响回收效率
回收过程分三阶段推进
整个回收流程包含标记、回收、特殊处理三个逻辑阶段,不同代采用不同策略:
- 标记阶段:使用三色标记法(白/灰/黑)确保准确性,期间必须 STW(暂停应用线程),防止引用关系变动导致漏标或错标
-
回收阶段:
- 新生代(Eden + Survivor)主要用复制算法:将存活对象复制到空闲 Survivor 区,清空原区域;对象每经历一次 Minor GC 年龄+1,达阈值(默认15)或大对象直接晋升老年代
- 老年代常用标记-清除(CMS)或标记-整理(G1、ZGC):前者快但产生碎片,后者移动对象避免碎片但耗时稍长
-
特殊处理阶段:区分四种引用类型行为:
- 强引用:只要存在,绝不回收
- 软引用:内存不足时才回收(适合缓存)
- 弱引用:每次 GC 都回收(适合临时映射)
- 虚引用:仅用于接收回收通知,不影响生命周期
哪些区域真正需要回收
JVM 内存中,只有堆(Heap)和方法区(Metaspace)是动态分配、需 GC 主动管理的区域。
- 程序计数器、虚拟机栈、本地方法栈属于线程私有,随线程创建而分配、销毁而释放,无需 GC 干预
- 堆是对象实例和数组的主要分配地,也是 GC 最频繁作用的区域
- 方法区(JDK 8+ 为 Metaspace)负责类元数据、常量、静态变量等,回收条件包括:类加载器被卸载、元空间容量超限(
-XX:MaxMetaspaceSize)
主流回收器如何优化停顿体验
为降低 STW 时间,现代收集器普遍引入并发机制:
- CMS:并发标记 + 重新标记(STW)+ 并发清除,但存在浮动垃圾,且无法处理碎片膨胀
-
G1:将堆划分为多个 Region,优先回收垃圾最多的区域(Garbage-First),支持可预测停顿时间(
-XX:MaxGCPauseMillis) - ZGC / Shenandoah:通过读屏障(Load Barrier)实现几乎全并发标记与压缩,停顿稳定控制在 10ms 以内,适合超低延迟场景











