JVM(Java虚拟机)的垃圾回收(Garbage Collection, GC)机制是Java内存管理的核心,它自动回收不再使用的对象内存,避免了手动内存管理的复杂性和潜在错误。以下是其核心原理和实现细节:
JVM内存模型与GC目标
JVM内存主要分为以下几个区域,GC主要针对堆内存进行回收:
- 堆(Heap):存放对象实例,分为:
- 新生代(Young Generation):新对象在此分配,分为 Eden 区和两个 Survivor 区(S0, S1)。
- 老年代(Old Generation):存活时间较长的对象晋升至此。
- 元空间(Metaspace):存放类元数据(JDK8+替代永久代)。
- 栈(Stack):存放方法调用和局部变量,无需GC。
- 方法区(Method Area):存储类结构,JDK8后由元空间实现。
垃圾回收的核心原理
- 判断对象是否存活:
- 引用计数法(JVM未采用):存在循环引用问题。
- 可达性分析(JVM实际使用):从GC Roots(如栈帧变量、静态变量、JNI句柄等)出发,遍历所有引用链,不可达的对象标记为“可回收”。
- 垃圾回收算法:
- 标记-清除(Mark-Sweep):标记无用对象后直接清除。缺点:内存碎片。
- 复制(Copying):将存活对象复制到另一块内存(如新生代的Survivor区)。优点:无碎片;缺点:空间浪费。
- 标记-整理(Mark-Compact):标记后整理存活对象到内存一端。优点:适合老年代。
- 分代收集(Generational Collection):结合以上算法,新生代用复制,老年代用标记-清除或标记-整理。
垃圾回收触发条件
- Minor GC:当新生代Eden区满时触发,存活对象复制到Survivor区,年龄达到阈值(默认15)后晋升老年代。
- Full GC:触发条件包括:
- 老年代空间不足。
- 方法区空间不足。
- 调用
System.gc()
(不保证执行)。 - Minor GC后存活对象过多,Survivor区无法容纳。
内存分配策略
- 对象优先在Eden分配:多数对象朝生夕灭。
- 大对象直接进老年代:避免在Survivor区复制。
- 长期存活对象晋升老年代:对象年龄计数器记录存活次数。
- 动态年龄判断:Survivor区中相同年龄对象总大小超过阈值时,直接晋升。
GC调优与监控
- 常用参数:
-Xmx
/-Xms
:堆最大/初始大小。-XX:NewRatio
:老年代与新生代比例。-XX:SurvivorRatio
:Eden与Survivor区比例。-XX:+UseG1GC
:启用G1收集器。
- 工具:
jstat
:查看GC统计信息。jmap
:生成堆转储快照。VisualVM
/GCEasy
:可视化分析GC日志。
常见问题与解决
- 频繁Full GC:检查内存泄漏、老年代空间配置。
- GC停顿过长:切换低延迟收集器(如G1/ZGC)。
- 内存泄漏:通过堆转储分析对象引用链。
总结
JVM的垃圾回收机制通过分代、多算法结合,平衡了内存使用效率和停顿时间。理解其原理及收集器特性,结合实际场景调优,是保障Java应用性能的关键。