JVM内存回收算法的核心是“清什么”和“怎么清得又快又稳”:先通过可达性分析(以GC Roots为起点)判定可回收对象,再依场景选用标记-清除(老年代,有碎片)、标记-整理(老年代,无碎片但开销大)或标记-复制(新生代,无碎片、高效但空间利用率低),并结合分代回收、TLAB等优化机制提升整体效率。

JVM内存回收算法的核心,不是“怎么清”,而是“清什么”和“怎么清得又快又稳”。面试常考的几类算法,背后都对应着明确的设计取舍:空间换时间、停顿换吞吐、碎片换效率。
怎么判断对象该回收?——可达性分析是唯一答案
引用计数法虽然直观,但因循环引用问题已被JVM彻底弃用。所有现代JVM都依赖可达性分析:从GC Roots出发,沿着引用链向下搜索。不可达的对象才被标记为可回收。
GC Roots主要包括:
- 虚拟机栈中正在使用的局部变量(如方法参数、栈内对象引用)
- 方法区中的静态变量(static修饰的类字段)
- 方法区中的常量(final static引用的对象)
- 本地方法栈中JNI引用的对象
注意:对象引用设为null只是断开一条路径,是否真正可回收,取决于它是否还被其他Root或存活对象间接引用。
三种基础回收算法各干啥?——匹配不同内存区域
没有万能算法,只有合适场景:
- 标记-清除(Mark-Sweep):先标记所有存活对象,再统一清除未标记部分。优点是只遍历一次,缺点是产生内存碎片,老年代偶尔使用(如Serial Old)
- 标记-整理(Mark-Compact):标记后把存活对象向一端压缩,再清理边界外内存。避免碎片,但移动对象带来额外开销,适用于老年代(如CMS的并发整理阶段、G1的混合回收)
- 标记-复制(Mark-Copy):把存活对象复制到另一块空闲区域,原区域直接清零。无碎片、分配快,但需预留双倍空间——因此专用于新生代(Eden + Survivor区)
为什么分代回收?——利用对象生命周期的天然分布
统计表明,95%以上的新对象朝生暮死。分代回收正是基于这一事实设计:
- 新生代用复制算法:存活率低,复制成本小;Survivor区两次熬过Minor GC才进入老年代
- 老年代对象存活率高,复制代价大,改用标记-清除或标记-整理
- 方法区(元空间)回收极少发生,仅在Full GC时尝试卸载无用类,且必须同时满足三个条件:该类所有实例已回收、Class对象无引用、加载该类的类加载器也无引用
这种划分不是硬编码,而是JVM根据实际对象年龄、晋升阈值、GC日志动态调优的结果。
TLAB与分配优化——回收前的“省力”设计
回收效率不仅靠算法,也靠减少待回收对象数量和降低分配压力:
- TLAB(Thread Local Allocation Buffer)让每个线程在Eden区拥有私有小块内存,避免多线程竞争指针,提升分配速度
- 大对象(如长数组)直接分配到老年代,绕过新生代复制,防止频繁触发Minor GC
- 逃逸分析可能将短生命周期对象栈上分配,根本不上堆,自然无需GC
这些机制不改变回收算法本身,却显著降低了GC频率和单次工作量。

















