1. 垃圾回收的基本概念
什么是垃圾?
当一个或多个对象没有任何引用指向它们时,这些对象就成为了垃圾,可能会被垃圾回收器回收。
垃圾识别算法
- 引用计数法:对象被引用时计数+1,引用失效时计数-1,计数为0时可回收。存在循环引用问题,现在基本不用。
- 可达性分析算法:从GC Roots开始,通过引用链判断对象是否可达。不可达的对象可被回收。这是主流的垃圾识别算法。
GC Roots包括:虚拟机栈中的引用、方法区中的静态变量和常量、本地方法栈中的引用、活跃线程等。
2. 垃圾回收算法
标记-清除算法(Mark-Sweep)
- 过程:标记所有需要回收的对象,然后清除这些对象
- 优点:标记和清除速度较快,不需要移动对象
- 缺点:产生内存碎片,影响大对象分配
标记-整理算法(Mark-Compact)
- 过程:标记后将存活对象向内存一端移动,清理掉边界外的内存
- 优点:解决了内存碎片问题
- 缺点:需要移动对象,效率相对较低
复制算法(Copying)
- 过程:将内存分为两块,每次只使用一块,回收时将存活对象复制到另一块
- 优点:回收效率高,无内存碎片
- 缺点:内存利用率只有50%
分代收集算法
不同代使用不同算法:新生代使用复制算法,老年代使用标记-清除或标记-整理算法。
3. JVM内存分代模型
堆内存划分
- 新生代:老年代 = 1:2
- 新生代内部:Eden:Survivor0:Survivor1 = 8:1:1
对象分配和晋升过程
- 新对象优先分配到Eden区
- Eden区满时触发Minor GC,存活对象复制到Survivor区
- Survivor区中对象每经历一次GC,年龄+1
- 年龄达到15(默认)或Survivor区空间不足时,对象晋升到老年代
- 大对象(超过Eden区一半)直接进入老年代
4. GC类型详解
Minor GC(Young GC)
- 触发条件:Eden区空间不足
- 回收范围:新生代
- 特点:频率高,耗时短
Major GC
- 触发条件:老年代空间不足
- 回收范围:老年代
- 特点:频率低,耗时长
Full GC
- 触发条件:整个堆空间不足、方法区空间不足、System.gc()调用等
- 回收范围:整个堆 + 方法区
- 特点:耗时最长,应尽量避免
Mixed GC
- 回收范围:新生代 + 老年代部分区域
- 特点:G1收集器特有
5. 垃圾收集器对比
串行收集器(Serial/SerialOld)
- 特点:单线程收集,STW时间长
- 适用场景:单核CPU、小内存应用
- 算法:新生代使用复制算法,老年代使用标记-整理算法
并行收集器(ParallelNew/ParallelOld)
- 特点:多线程收集,JDK8默认收集器
- 适用场景:多核CPU、注重吞吐量的应用
- 算法:新生代使用复制算法,老年代使用标记-整理算法
CMS收集器(Concurrent Mark Sweep)
- 特点:并发收集,低延迟,使用标记-清除算法
- 适用场景:注重响应时间的应用
- 缺点:产生内存碎片,可能发生并发失败
G1收集器(Garbage First)
- 特点:JDK9+默认收集器,兼顾吞吐量和延迟
- 内存模型:将堆划分为多个Region,每个Region可以是Eden、Survivor、Old、Humongous
- 回收过程:新生代回收 → 并发标记 → 混合收集
- 优点:可预测的停顿时间,适合大内存应用
6. 引用类型详解
强引用(Strong Reference)
- 特点:最常见的引用类型,如
Object obj = new Object()
- 回收条件:只有当GC Roots不可达时才会被回收
- 使用场景:一般对象引用
软引用(Soft Reference)
- 特点:内存不足时会被回收
- 回收条件:在内存不足时,即使有软引用指向,也会被回收
- 使用场景:内存敏感的缓存
弱引用(Weak Reference)
- 特点:下次GC时必定被回收
- 回收条件:只要发生GC,无论内存是否充足都会被回收
- 使用场景:ThreadLocal防止内存泄漏
虚引用(Phantom Reference)
- 特点:最弱的引用类型,无法通过虚引用获取对象
- 使用场景:配合引用队列使用,监控对象回收,管理直接内存
7. 面试高频问题
如何判断对象可以被回收?
通过可达性分析算法,从GC Roots开始遍历引用链,不可达的对象可以被回收。
什么情况下会发生Full GC?
- 老年代空间不足
- 方法区空间不足
- 通过Minor GC后进入老年代的对象大小超过老年代可用内存
- 手动调用System.gc()
如何优化GC性能?
- 合理设置堆内存大小
- 选择合适的垃圾收集器
- 优化代码,减少不必要的对象创建
- 避免内存泄漏
- 调整新生代和老年代的比例
G1收集器的优势?
- 低延迟:可预测的停顿时间
- 高吞吐量:并发收集,减少STW时间
- 内存整理:避免内存碎片
- 适合大内存:Region化管理,适合大堆应用
8. 调优建议
常用JVM参数
-Xms
:初始堆大小-Xmx
:最大堆大小-Xmn
:新生代大小-XX:SurvivorRatio
:Eden和Survivor比例-XX:MaxTenuringThreshold
:对象晋升老年代的年龄阈值-XX:+UseG1GC
:使用G1收集器
监控工具
- JConsole:JVM自带的监控工具
- VisualVM:可视化监控工具
- JProfiler:商业性能分析工具
- GC日志分析:通过-XX:+PrintGCDetails开启详细GC日志