
JVM垃圾回收详解(HotSpot虚拟机)
一、对象存活判定
-
引用计数法
• 原理:为对象添加引用计数器,引用时+1,失效时-1,计数器为0时判定可回收。
• 缺点:无法解决循环引用问题(如两个对象互相引用但无外部引用)。 -
可达性分析法
• 原理:从GC Roots出发,通过引用链判断对象是否可达。不可达对象被标记为可回收。
• GC Roots 类型:
◦ 虚拟机栈中局部变量引用的对象
◦ 方法区中类静态属性、常量引用的对象
◦ JNI(Native方法)引用的对象
◦ 所有被同步锁持有的对象 -
对象的两次标记过程
• 第一次标记:不可达对象被筛选是否需要执行finalize()
方法(若未覆盖或已执行过则跳过)。
• 第二次标记:若对象未在finalize()
中重新关联引用链,则被回收。
二、引用类型
-
强引用(Strong Reference)
• 最常见的引用类型(如Object obj = new Object()
)。
• 即使内存不足也不会被回收,可能导致OutOfMemoryError
。 -
软引用(Soft Reference)
• 内存不足时回收,适合实现缓存(如SoftReference<String> softRef
)。 -
弱引用(Weak Reference)
• 下一次GC时被回收(如WeakReference<String> weakRef
)。
• 常用于WeakHashMap
。 -
虚引用(Phantom Reference)
• 无法通过虚引用访问对象,仅用于跟踪对象被回收的活动(需配合ReferenceQueue
)。
三、废弃常量与无用类
-
废弃常量
• 常量池中的常量(如字符串"abc")无任何引用时被回收。 -
无用类
• 满足以下条件:
◦ 所有实例已被回收。
◦ 加载该类的ClassLoader
已被回收。
◦ 对应的Class
对象未被引用,无法通过反射访问。
四、垃圾收集算法
-
标记-清除(Mark-Sweep)
• 步骤:标记存活对象,清除未标记对象。
• 缺点:内存碎片、效率问题。 -
复制算法(Copying)
• 步骤:将内存分为两块,存活对象复制到另一块,清空原区域。
• 适用场景:新生代(Eden区、Survivor区)。
• 缺点:内存利用率低(默认新生代 Eden:S0:S1=8:1:1)。 -
标记-整理(Mark-Compact)
• 步骤:标记存活对象后,向一端移动并清理边界外内存。
• 适用场景:老年代。 -
分代收集算法
• 新生代:复制算法(对象存活率低)。
• 老年代:标记-清除或标记-整理算法(对象存活率高)。
五、分代模型(新生代与老年代)
-
分代原因
• 不同对象生命周期差异大,分代可优化回收效率。
• 新生代对象存活时间短,适合高频回收;老年代对象存活时间长,低频回收。 -
对象晋升规则
• 年龄计数器:对象每熬过一次Minor GC,年龄+1。
• 阈值:默认15岁(可通过-XX:MaxTenuringThreshold
调整)。
• 动态年龄判定:若某年龄对象总大小超过Survivor区50%(-XX:TargetSurvivorRatio
),则直接晋升。
六、垃圾收集器
-
Serial收集器
• 特点:单线程,STW(Stop-The-World)时间长。
• 适用场景:Client模式、小内存应用。 -
ParNew收集器
• 特点:Serial的多线程版本,与CMS配合使用。 -
Parallel Scavenge/Old收集器
• 特点:关注吞吐量(CPU利用率),适合后台计算任务。 -
CMS(Concurrent Mark Sweep)
• 步骤:初始标记(STW)→并发标记→重新标记(STW)→并发清除。
• 优点:低停顿。
• 缺点:内存碎片、CPU敏感。
• 淘汰:JDK9后标记为过时,JDK14移除。 -
G1(Garbage-First)
• 特点:
◦ 将堆划分为多个Region(默认2048个),优先回收价值高的Region。
◦ 可预测停顿时间(-XX:MaxGCPauseMillis
)。
• 步骤:初始标记→并发标记→最终标记→筛选回收。
• 适用场景:大内存、低延迟要求(JDK9后默认)。 -
ZGC
• 特点:亚毫秒级停顿,支持16TB堆内存(JDK15正式可用)。
七、GC类型与触发条件
-
Minor GC
• 区域:新生代(Eden区满时触发)。
• 特点:高频、快速。 -
Full GC
• 区域:整个堆(包括老年代、方法区)。
• 触发条件:
◦ 老年代空间不足。
◦ 方法区(元空间)不足。
◦ 空间分配担保失败(老年代连续空间不足)。
八、调优与监控
-
参数调优
•-Xms
/-Xmx
:初始堆/最大堆大小。
•-XX:NewRatio
:新生代与老年代比例。
•-XX:SurvivorRatio
:Eden区与Survivor区比例。 -
工具
•jstat
:监控GC状态。
•jmap
:堆内存分析。
•VisualVM
:图形化监控。
九、关键总结
• 分代模型:优化回收效率,不同区域采用不同算法。
• 引用类型:强引用不回收,软/弱引用根据内存压力回收,虚引用跟踪回收。
• 收集器选择:
• 低延迟:G1、ZGC。
• 高吞吐:Parallel Scavenge/Old。
• Full GC避免:合理分配内存,避免大对象直接进入老年代,监控元空间使用。
通过理解上述机制,可有效解决内存溢出问题,优化JVM性能。