jvm垃圾回收全流程以对象生命周期为主线:新对象分配在eden区,minor gc后存活对象移至survivor并年龄+1,达阈值或空间不足时晋升老年代;大对象直接入老年代;老年代满触发major/full gc。算法层面,新生代用复制算法(高效无碎片),老年代用标记-清除(cms)或标记-整理(serial old、zgc);引用类型决定回收时机,强引用不回收,软/弱/虚引用依次放宽条件;gc日志中real时间反映stw停顿,内存变化与触发原因助力精准调优。

掌握 JVM 垃圾回收全流程,关键不是背参数或记名字,而是理清“对象从出生到消亡”的完整路径,以及每个环节背后的设计意图。只要这条主线清晰了,收集器、算法、日志、调优就自然串得起来。
搞懂内存分区与对象生命周期
堆是 GC 的主战场,必须分清新生代(Eden + 2 个 Survivor)和老年代的分工逻辑:
- 新对象默认分配在 Eden 区;Eden 满时触发 Minor GC,存活对象复制到 To Survivor,并年龄 +1
- 对象在 Survivor 中每熬过一次 Minor GC,年龄加 1;达到阈值(默认 15)或 Survivor 空间不足时,晋升到老年代
- 大对象(如大数组)可能直接进入老年代,避免在 Survivor 区反复复制
- 老年代空间不足会触发 Major GC 或 Full GC,通常比 Minor GC 耗时更长、影响更大
理解三种基础回收算法的本质区别
所有收集器都基于这三种算法演化而来,知道“为什么用这个算法”比记住“哪个收集器用了哪个算法”更重要:
- 复制算法:用于新生代。把存活对象从 From 复制到 To,清空 From。优势是无碎片、分配快;代价是浪费一半空间
- 标记-清除:用于 CMS(已废弃)等老年代收集器。先标记存活对象,再清理未标记的。优势是不移动对象;缺点是产生内存碎片
- 标记-整理:用于 Serial Old、Parallel Old、ZGC 等。标记后把存活对象往一端压缩,再清理边界外内存。解决碎片问题,但移动成本高
分清四类引用对回收时机的影响
引用类型决定了对象是否能被回收,也是缓存、监听器泄漏等问题的根源:
- 强引用:Object obj = new Object() —— GC 永远不回收,即使 OOM
- 软引用:SoftReference —— 内存不足时才回收,适合做缓存
- 弱引用:WeakReference —— 下次 GC 就回收,适合临时映射(如 WeakHashMap)
- 虚引用:PhantomReference —— 仅用于跟踪对象被回收的时刻,必须配合 ReferenceQueue 使用
会看 GC 日志,才能定位真实问题
日志不是装饰,是诊断依据。重点关注几类信息:
- GC 类型:ParNew(新生代)、ConcurrentMarkSweep(CMS,JDK9+ 已移除)、G1 Mixed GC、ZGC Pause、Shenandoah Cycle 等
- 耗时指标:[Times: user=0.12 sys=0.01, real=0.038s] 中的 real 是 STW 时间,是性能瓶颈的关键信号
- 内存变化:GC 前后各区域大小(如 Eden: 1024M->128M),能看出对象晋升是否异常、是否存在内存泄漏
- 触发原因:Allocation Failure(分配失败)、Metadata GC Threshold(元空间满)、System.gc()(代码主动触发)等










