1. 什么是 GC?
- GC(Garbage Collection):JVM 自动回收不再使用的对象内存,避免内存泄漏。
- 程序员不用手动释放内存,JVM 帮你“打扫垃圾”。
2. 堆内存结构(GC 主战场)
堆 = 新生代(Young Gen) + 老年代(Old Gen)
- 新生代:新创建的对象先放这里。又分为:
- Eden 区:对象出生地。
- Survivor S0 / S1:幸存者区,用于存放经过一次 GC 还活着的对象。
- 老年代:长期存活的对象最终移入这里。
💡 类比:新生代像“幼儿园”,老年代像“养老院”。
3. 常见 GC 算法
| 算法 | 特点 | 适用区域 |
|---|---|---|
| 标记-清除(Mark-Sweep) | 标记活对象,清除死对象;会产生碎片 | 老年代 |
| 复制(Copying) | 把活对象复制到另一块空间,清空原空间;无碎片但浪费内存 | 新生代 |
| 标记-整理(Mark-Compact) | 标记后把活对象“挤”到一端,再清理边界外 | 老年代 |
4. 常见 GC 收集器(JDK 8 为主)
| 收集器 | 类型 | 特点 | 适用场景 |
|---|---|---|---|
| Serial | 单线程 | 简单高效,STW(Stop-The-World) | 单核/小内存 |
| ParNew | 多线程版 Serial | 配合 CMS 使用 | 中小型应用 |
| Parallel Scavenge + Parallel Old | 吞吐量优先 | 最大化 CPU 利用率 | 后台计算、批处理 |
| CMS(Concurrent Mark Sweep) | 低延迟 | 并发执行,减少停顿 | Web 应用(已废弃) |
| G1(Garbage First) | 分区+并发 | 可预测停顿时间,兼顾吞吐与延迟 | 大堆(>4GB)、低延迟要求 |
| ZGC / Shenandoah | 超低延迟 | 停顿 <10ms,JDK11+(实验),JDK15+(正式) | 极致响应要求 |
✅ JDK 8 推荐:G1(堆 > 4GB)或 Parallel(追求吞吐)
5. GC 触发时机
- Minor GC:Eden 区满 → 清理新生代(快,频繁)
- Major GC / Full GC:老年代满 or 元空间满 → 清理整个堆(慢,应尽量避免)
⚠️ Full GC 会导致长时间 STW,严重影响性能!
6. 关键调优目标
| 目标 | 说明 |
|---|---|
| 降低 Full GC 次数 | 通过合理分配堆大小、调整对象晋升年龄等 |
| 控制 GC 停顿时间 | 选择合适收集器(如 G1) |
| 提高吞吐量 | 减少 GC 时间占比(如用 Parallel) |
7. 常用 JVM 参数(JDK 8 示例)
# 堆大小
-Xms4g -Xmx4g # 初始 & 最大堆(建议设为相同,避免动态扩容)
# 新生代大小
-Xmn2g # 新生代大小(一般为堆的 1/3~1/2)
# 选择 GC
-XX:+UseG1GC # 使用 G1
-XX:+UseParallelGC # 使用 Parallel(默认)
# G1 调优
-XX:MaxGCPauseMillis=200 # 目标最大停顿时间(毫秒)
-XX:G1HeapRegionSize=16m # Region 大小(可选)
# 打印 GC 日志(排查必备)
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:/path/to/gc.log
8. 调优步骤(实战流程)
- 监控:用
jstat -gc <pid>或 GC 日志观察 GC 频率、停顿时间。 - 分析:
- Minor GC 频繁?→ Eden 太小 or 对象太多。
- Full GC 频繁?→ 老年代不够 or 内存泄漏。
- 调整:
- 增大堆 or 调整新生代比例。
- 切换更合适的 GC 收集器。
- 验证:压测 + 观察 GC 日志是否改善。
9. 小贴士(避坑指南)
- 不要盲目调大堆:堆越大,GC 停顿可能越长(除非用 G1/ZGC)。
- 避免内存泄漏:静态集合、未关闭资源等会导致对象无法回收。
- 生产环境务必开 GC 日志:这是诊断性能问题的“黑匣子”。
🌟 记住:GC 调优不是“一次搞定”,而是“监控 → 分析 → 调整 → 验证”的循环过程。
✅ 本笔记覆盖 GC 核心概念、算法、收集器、参数、调优方法,语言通俗,适合快速掌握和复习。