🧠 一、GC基础概念
1. 什么是垃圾回收(Garbage Collection, GC)?
- 作用:自动管理内存,回收不再使用的对象,防止内存泄漏和溢出。
- 核心问题:
(1) 如何判断对象是垃圾?
(2)如何高效回收垃圾?
2. 判断对象是否为垃圾的方法
方法 |
说明 |
引用计数法 |
每个对象维护一个引用计数器,引用增加时计数+1,引用失效时-1。无法解决循环引用问题。 |
可达性分析法 |
从GC Roots出发,不可达的对象判定为垃圾。GC Roots包括:虚拟机栈中的局部变量、类静态属性引用、常量引用、JNI引用。 |
🧩 二、GC核心算法
1. 标记-清除算法(Mark-Sweep)
- 步骤:
(1)标记:从GC Roots出发,标记所有存活对象。
(2)清除:回收未被标记的对象。
- 缺点:
(1)产生内存碎片(可能导致大对象分配失败)。
(2)标记和清除效率较低。
2. 标记-整理算法(Mark-Compact)
- 步骤:
(1)标记:同标记-清除。
(2)整理:将存活对象向一端移动,清理边界外内存。
- 优点:避免内存碎片。
- 缺点:移动对象需要暂停所有线程(Stop-The-World)。
3. 复制算法(Copying)
- 步骤:
(1)将内存分为两块,每次只用一块。
(2)回收时,将存活对象复制到另一块,清空原区域。
- 优点:高效,无内存碎片。
- 缺点:内存利用率低(只使用一半)。
4. 分代收集算法(Generational Collection)
- 思想:将堆内存划分为新生代(Young Generation)和老年代(Old Generation)。
- 新生代:对象生命周期短,使用复制算法。
- 老年代:对象生命周期长,使用标记-清除或标记-整理。
📌 三、主流垃圾收集器
1. Serial 收集器(串行)
- 特点:单线程,适用于单核CPU或小内存场景。
- 使用场景:Client模式(如桌面应用)。
- 命令行参数:
-XX:+UseSerialGC
2. Parallel Scavenge 收集器(并行)
- 特点:多线程,关注吞吐量(吞吐优先)。
- 使用场景:后台计算任务(如批量处理)。
- 命令行参数:
-XX:+UseParallelGC
3. CMS(Concurrent Mark Sweep)收集器(并发)
- 目标:以最短停顿时间为目标,适合高并发、低延迟的Web应用。
- 回收步骤:
(1)初始标记(Initial Mark):暂停所有线程,标记GC Roots直接关联的对象。
(2)并发标记(Concurrent Mark):并发标记所有存活对象。
(3)重新标记(Remark):暂停线程,处理并发标记期间新增的对象。
(4)并发清除(Concurrent Sweep):并发清除垃圾对象。
- 优点:低停顿时间。
- 缺点:
(1)内存碎片化(可能导致Full GC)。
(2)对CPU资源敏感。
- 命令行参数:
-XX:+UseConcMarkSweepGC
4. G1(Garbage-First)收集器(分区)
- 目标:兼顾吞吐量和低延迟,适用于大内存(>6GB)和多核CPU。
- 核心思想:
(1) 将堆内存划分为多个Region(大小相等,1~32MB)。
(2) 优先回收垃圾最多的Region。
- 回收步骤:
(1)初始标记(Initial Mark):暂停线程,标记GC Roots。
(2)并发标记(Concurrent Mark):并发标记存活对象。
(3)最终标记(Final Mark):处理并发标记期间新增的对象。
(4)筛选回收(Live Data Counting and Evacuation):选择回收价值高的Region进行回收。
- 优点:
可预测的停顿时间(通过 -XX:MaxGCPauseMillis 设置)。
避免内存碎片(回收时进行压缩)。
- 缺点:
内存占用较高(维护Region状态)。
- 命令行参数:
-XX:+UseG1GC
🧱 四、GC收集器对比总结

🔄 五、GC类型与触发条件

🧪 六、常见GC异常与调优
1. 内存泄漏(Memory Leak)
- 原因:对象不再使用但无法被GC回收(如缓存未清理、监听器未注销)。
- 定位工具:
(1) MAT(Memory Analyzer):分析堆转储(heap dump)。
(1) VisualVM:实时监控内存使用情况。
(3) jmap + jhat:生成并分析堆转储。
2. 内存溢出(OutOfMemoryError)
- 常见类型:
- Java heap space:堆内存不足。
- GC overhead limit exceeded:GC频繁且效率低。
- PermGen / Metaspace:方法区或元空间内存不足。
- 解决方法:
- 增加堆大小(-Xmx)。
- 调整元空间大小(-XX:MaxMetaspaceSize)。
- 优化代码(减少对象创建、及时释放资源)。
3. GC调优目标
目标 |
说明 |
吞吐量(Throughput) |
单位时间内处理任务的效率(适合后台计算任务) |
停顿时间(Pause Time) |
每次GC暂停的时间(适合Web服务) |
内存占用(Footprint) |
堆内存使用量(适合内存敏感场景) |
4. GC调优常用参数
参数 |
说明 |
-Xms / -Xmx |
设置堆初始和最大大小(如 -Xms2g -Xmx4g) |
-XX:NewRatio |
新生代与老年代比例(默认1:2) |
-XX:SurvivorRatio |
Eden与Survivor比例(默认8:1:1) |
-XX:MaxGCPauseMillis |
G1收集器的目标停顿时间(默认200ms) |
-XX:G1HeapRegionSize |
G1的Region大小(1~32MB) |
-XX:+PrintGCDetails |
打印详细GC日志 |
-XX:+PrintGCDateStamps |
打印GC时间戳 |
-Xloggc:/path/to/gc.log |
输出GC日志到文件 |
🧩 七、常见GC问题排查工具
工具 |
说明 |
jstat |
实时监控GC状态(如 jstat -gc 1234 1000 每秒输出GC信息) |
jmap |
生成堆转储(jmap -dump:format=b,file=heap.bin 1234) |
jhat |
分析堆转储(jhat heap.bin) |
VisualVM |
图形化监控JVM内存、线程、GC等 |
MAT(Memory Analyzer) |
分析堆转储,定位内存泄漏 |
GC |
日志分析工具 如 GCViewer、GCEasy、GCPlot |
📋 八、常见面试题及答案
1. CMS 和 G1 的区别?

2. G1为何适合大内存?
- 分区管理:将堆划分为多个Region,可并行回收。
- 可预测停顿:通过 -XX:MaxGCPauseMillis 设置目标停顿时间。
- 避免碎片化:回收时进行压缩(Evacuation阶段)。
3. CMS的缺点?
- 内存碎片化:可能导致Full GC(标记-清除算法的缺点)。
- 并发阶段耗CPU:并发标记和清除阶段占用CPU资源。
- Concurrent Mode Failure:老年代空间不足导致并发失败,退化为Serial Old收集器。
4. 如何选择合适的GC收集器?

5. Full GC的触发条件?
- 老年代空间不足。
- 方法区(元空间)内存不足。
- 调用 System.gc()(可禁用 -XX:+DisableExplicitGC)。
- 分配大对象(如大数组)。
6. 如何优化GC性能?
- 合理设置堆大小:避免频繁GC。
- 避免内存泄漏:使用缓存时注意释放。
- 选择合适收集器:如G1适合大内存。
- 监控GC日志:分析停顿时间和频率。
📚 九、GC调优实践建议

✅ 十、总结:GC机制核心知识点

📄 十一、完整GC日志示例
2023-10-23T15:30:00.123+0800: [GC (Allocation Failure) [PSYoungGen: 131072K->15360K(157248K)] 131072K->15360K(503936K), 0.0123456 secs] [Times: user=0.05 sys=0.00, real=0.01 secs]
日志解析:
- GC类型:Allocation Failure(分配失败触发GC)。
- GC区域:PSYoungGen(Parallel Scavenge新生代)。
- 内存变化:131072K->15360K(回收后内存占用)。
- 耗时:0.0123456 secs(GC耗时)。
📌 十二、推荐学习资料
- 《深入理解 Java 虚拟机》(周志明)
- 《Java 性能调优指南》
- JVM 官方文档:https://docs.oracle.com/en/java/javase/17/gctuning/
- GC日志分析工具:GCViewer、GCEasy、GCPlot
- JVM调优视频教程(B站、慕课网、CSDN)