知识点深化 · JVM · 垃圾回收
垃圾回收:GC Roots、标记清除/复制/整理、CMS/G1/ZGC
GC 自动回收堆中不再被引用的对象。它先从 GC Roots 出发标记存活对象,再用不同算法回收死对象;分代假设下新生代用复制、老年代用标记整理。CMS、G1、ZGC 是三代经典收集器。这一页把判断、算法、收集器讲透。
① 小白第一课怎么学(4 步走,约 60 分钟)
别急着背代码,先按这四步建立直觉:
1看图建立直觉(10 分钟)
读②③:GC 怎么找活对象。
2记算法与分代(15 分钟)
读④:标记清除/复制/整理,新生代老年代。
3手推回收(20 分钟)
精读⑤。
4刷题纠错(15 分钟)
做⑦⑩,错题回⑥。
本课小目标学完你要能:① 说什么对象可回收;② 对比三种基础算法;③ 讲清 G1 和 ZGC 的特点。
② 一图看懂:GC 全地图
读法:中心是垃圾回收,上是判断存活,中是算法,下是收集器与易错。
③ 本质直觉:从 GC Roots 出发,够得到的活着,够不到的回收
怎么判断垃圾:从 GC Roots(栈里局部变量、静态变量、常量等)出发沿引用链走,能到达的对象是活的,到不了的是死的。这叫可达性分析。(引用计数法解决不了循环引用,Java 不用。)
三种回收算法:① 标记-清除:标记死对象直接清,产生碎片;② 复制:存活对象拷到另一半,无碎片但浪费一半空间,适合新生代(存活率低);③ 标记-整理:存活对象往一端挪,无碎片但慢,适合老年代。
分代:新对象朝生夕死 → 新生代用复制;老对象活得久 → 老年代用标记整理。
STWGC 时要暂停所有应用线程(Stop The World),否则引用关系还在变。G1/ZGC 的目标就是缩短这个停顿。
④ 完整体系与对比表
三种算法对比
| 算法 | 做法 | 优点 | 缺点 |
| 标记-清除 | 标记死对象直接清 | 简单 | 内存碎片 |
| 复制 | 存活对象拷到另一半 | 无碎片、快 | 浪费一半空间 |
| 标记-整理 | 存活对象挪到一端 | 无碎片 | 移动开销大、慢 |
分代与收集器
新生代(Eden + 2 Survivor):新对象先进 Eden,Minor GC 时存活对象复制到 Survivor,年龄每次+1,达到阈值(默认15)进老年代。用复制算法。
老年代:存存活久的对象,满了触发 Full GC,用标记-整理。
| 收集器 | 特点 |
| CMS | 低停顿并发标记清除,老年代,有碎片 |
| G1 | Region 化,可预测停顿,JDK9+ 默认 |
| ZGC | 着色指针/读屏障,停顿 <10ms,超大堆 |
⑤ 用法场景与典型例题
例1(GC Roots)下列哪个不能当 GC Roots?
栈局部变量、静态变量、常量可以。
GC Roots 包括虚拟机栈局部变量、方法区静态变量、常量、JNI 引用。答案:堆里普通对象互相引用不能当 Root(那是引用链不是起点)。
例2(算法选择)新生代存活率低用哪种?
复制划算。
存活少则拷贝量小,复制算法无碎片。答案:复制算法。
例3(停顿)G1 相比 CMS 的优势?
Region 化可预测停顿。
G1 把堆切成多个 Region,优先回收垃圾多的 Region,可设定 -XX:MaxGCPauseMillis。答案:可预测停顿、无碎片。
做题心法新生代→复制,老年代→整理;低延迟大堆→G1/ZGC;面试先问 STW 停顿。
⑥ 高频错误诊断(4 条)
错误1:用引用计数判断垃圾循环引用 A↔B 计数都不为 0,永远回收不掉。Java 用可达性分析。
错误2:以为 GC 只回收新生代老年代满了也会 Full GC 回收整个堆。
错误3:认为 CMS 没碎片CMS 是标记-清除,会产生碎片,最后不得不标记整理。
错误4:把 Minor GC 和 Full GC 混Minor GC 只回收新生代快;Full GC 回收整堆慢,要尽量避免。
⑦ 考点真题演练(4 题)
考点分布
| 考法 | 出题形式 | 应对 |
| 判断垃圾 | 用什么方法 | GC Roots 可达性分析 |
| 算法 | 新生代/老年代各用啥 | 复制/整理 |
| 收集器 | G1/ZGC 特点 | 可预测停顿/超低延迟 |
| STW | GC 为什么停顿 | 引用关系在变 |
真题基础1. Java 判断对象可回收使用?
真题中档2. 新生代通常使用哪种回收算法?
真题中档3. G1 收集器的核心优势是?
真题拔高4. 关于循环引用 A↔B(无外部引用),可达性分析会怎样?
⑧ 必背知识点卡
判断:GC Roots 可达性分析 解决循环引用
清除:直接清死对象 有碎片
复制:存活拷另一半 新生代
整理:存活挪一端 老年代无碎片
分代:新生代 Eden+Survivor 年龄15 升老年代
收集器:CMS/G1/ZGC G1 可预测停顿
STW:GC 暂停应用 越短越好
⑨ 应用输出:优化一次频繁 Full GC 的服务
场景:大促时服务频繁 Full GC,接口 RT 飙升。
① 看日志:加 -Xlog:gc 看 GC 频率和停顿,发现 Full GC 频繁。
② 定位:dump 堆,发现大集合(如缓存)只增不减——内存泄漏或堆太小。
③ 调参数:选 G1 收集器,设 -XX:MaxGCPauseMillis=200 控制停顿。
④ 修泄漏:给缓存加过期/上限,避免老年代被撑满。
⑤ 效果:Minor GC 为主,Full GC 降到每天一两次。
口述思路合上书说:"频繁 Full GC 先 dump 找泄漏大对象,再选 G1 控停顿。"
⑩ 分层练习(基础 + 中档 + 拔高)
▍基础 6 题
基础1Java 用什么判断垃圾?
GC Roots 可达性分析。
基础4GC Roots 是什么?
栈局部变量、静态变量等起点。
▍中档 6 题
中档7为什么引用计数被淘汰?
解决不了循环引用。
中档8Survivor 区有几个?
两个,from/to 交替。
中档9对象几岁进老年代?
默认 15(-XX:MaxTenuringThreshold)。
中档10G1 把堆分成什么?
多个等大 Region。
中档11ZGC 目标停顿?
亚毫秒级(<10ms),支持超大堆。
▍拔高 6 题
拔高13什么是空间分配担保?
新生代放不下时直接进老年代。
拔高14三色标记是什么?
黑(活)、灰(待扫)、白(未扫/垃圾),并发标记基础。
拔高15什么是记忆集 Card Table?
记录老年代引用新生代,避免扫整堆找跨代引用。
拔高16G1 的 Mixed GC 是什么?
同时回收新生代和部分高收益老年代 Region。
拔高17怎么减少 Full GC?
避免大对象直接进老年代、合理堆大小、修内存泄漏。
拔高18逃逸分析干嘛的?
判断对象是否逃出方法范围,可栈上分配减少 GC。
⑪ 记忆口诀 + 7 天复习计划
三句口诀① Roots 出发够着活,够不着的就是垃圾。② 新生代复制老年代整理,G1 控停顿 ZGC 超低延迟。③ 引用计数解不了循环引用,可达性才靠谱。
| 天 | 任务 | 自检 |
| 第 1 天 | 读②③④,画可达性分析 | 能说清 Roots |
| 第 2 天 | 背三算法 + 基础 1-6 | 算法对应对 |
| 第 3 天 | 做中档 7-12,说分代过程 | 晋升年龄对 |
| 第 4 天 | 做拔高 13-18,讲三色标记 | 能讲清并发 |
| 第 5 天 | 做⑦真题 4 题 | 限时每题 2 分钟 |
| 第 6-7 天 | 合上书默写算法对比表 | 不看资料全默对 |
← 返回软件技术总览