Java垃圾回收核心逻辑是:对象“不可达”即为垃圾,通过GC Roots可达性分析判定;采用分代回收策略,新生代用复制算法、老年代用标记-整理算法;Minor GC频发于Eden区满,Full GC代价最高;调优需紧盯GC频率、停顿时间与回收效果三大指标。

Java 垃圾回收考点精析,关键不在罗列概念,而在厘清逻辑链条:谁是垃圾 → 怎么判别 → 怎么回收 → 何时触发 → 如何调优。面试和实战中真正容易卡壳的,往往是环节之间的因果关系和边界条件。下面直击核心,分四块讲透。
怎么判断一个对象是“垃圾”?
不是“没用”,而是“不可达”。JVM 不看业务逻辑,只看引用链是否连通到 GC Roots。 - GC Roots 包括:栈帧里的局部变量、静态字段、本地方法栈中的 JNI 引用、正在运行的线程对象等; - 可达性分析从这些根出发,遍历所有强引用链,未被标记的对象即为待回收对象; - 引用计数法虽简单,但因无法处理循环引用(如 A.obj = B; B.obj = A; A = B = null),已被 HotSpot 完全弃用; - finalize() 不是“复活开关”,只是对象被回收前的最后一次回调机会,且不保证执行、不保证顺序、异常会被吞掉。垃圾回收用什么算法?各解决什么问题?
算法本质是权衡:空间效率 vs 时间开销 vs 内存碎片 vs 停顿时间。 - 标记-清除:先标存活对象,再清未标区域;优点是简单,缺点是产生内存碎片,影响大对象分配; - 复制算法:把存活对象复制到另一块空闲区(如 Survivor 区),原区域直接清空;适合新生代——对象朝生暮死,复制成本低; - 标记-整理:标记后把存活对象向一端移动,再清理边界外内存;解决碎片问题,但移动成本高,常用于老年代; - 分代收集不是独立算法,而是策略:结合上述算法,按对象年龄分区域管理(Eden、Survivor、Old),提升整体回收效率。不同 GC 类型触发场景和影响范围
GC 类型由回收区域决定,停顿时间和频率差异极大: - Minor GC:只回收新生代(Eden + Survivor),最频繁,通常停顿几毫秒;触发条件主要是 Eden 区满; - Major GC / Old GC:专指老年代回收(部分收集器如 CMS 可单独触发);实际中常与 Full GC 混用,但严格说不等价; - Full GC:回收整个堆(新生代 + 老年代)+ 元空间(Metaspace);代价最高,可能停顿数百毫秒甚至秒级;常见诱因包括老年代空间不足、元空间扩容失败、System.gc()(仅建议)、CMS 失败后降级等。调优时盯住哪几个关键指标?
脱离监控谈调优等于蒙眼开车。重点看三类信号: - 频率异常:Minor GC 间隔突然缩短 → 可能内存泄漏或对象生命周期过长; - 停顿过长:单次 GC 时间 > 200ms(响应敏感系统)→ 检查是否发生 Full GC 或老年代碎片化; - 回收无效:每次 GC 后老年代使用量持续上升 → 很可能是内存泄漏(如静态集合不断 add、未关闭的连接池); - 日志入口:加参数 `-Xlog:gc*:stdout:time,uptime,pid,tags`(JDK9+),重点关注 `GC pause`、`heap after`、`Metaspace` 使用量变化。不复杂但容易忽略。


















