JVM垃圾回收详解(重点) @ Lin | 2024-08-21T14:21:26+08:00 | 5 分钟阅读 | 更新于 2024-08-21T14:21:26+08:00

JVM垃圾回收详解(HotSpot虚拟机)


一、对象存活判定

  1. 引用计数法
    原理:为对象添加引用计数器,引用时+1,失效时-1,计数器为0时判定可回收。
    缺点:无法解决循环引用问题(如两个对象互相引用但无外部引用)。

  2. 可达性分析法
    原理:从GC Roots出发,通过引用链判断对象是否可达。不可达对象被标记为可回收。
    GC Roots 类型
    ◦ 虚拟机栈中局部变量引用的对象
    ◦ 方法区中类静态属性、常量引用的对象
    ◦ JNI(Native方法)引用的对象
    ◦ 所有被同步锁持有的对象

  3. 对象的两次标记过程
    • 第一次标记:不可达对象被筛选是否需要执行finalize()方法(若未覆盖或已执行过则跳过)。
    • 第二次标记:若对象未在finalize()中重新关联引用链,则被回收。


二、引用类型

  1. 强引用(Strong Reference)
    • 最常见的引用类型(如Object obj = new Object())。
    • 即使内存不足也不会被回收,可能导致OutOfMemoryError

  2. 软引用(Soft Reference)
    • 内存不足时回收,适合实现缓存(如SoftReference<String> softRef)。

  3. 弱引用(Weak Reference)
    • 下一次GC时被回收(如WeakReference<String> weakRef)。
    • 常用于WeakHashMap

  4. 虚引用(Phantom Reference)
    • 无法通过虚引用访问对象,仅用于跟踪对象被回收的活动(需配合ReferenceQueue)。


三、废弃常量与无用类

  1. 废弃常量
    • 常量池中的常量(如字符串"abc")无任何引用时被回收。

  2. 无用类
    • 满足以下条件:
    ◦ 所有实例已被回收。
    ◦ 加载该类的ClassLoader已被回收。
    ◦ 对应的Class对象未被引用,无法通过反射访问。


四、垃圾收集算法

  1. 标记-清除(Mark-Sweep)
    步骤:标记存活对象,清除未标记对象。
    缺点:内存碎片、效率问题。

  2. 复制算法(Copying)
    步骤:将内存分为两块,存活对象复制到另一块,清空原区域。
    适用场景:新生代(Eden区、Survivor区)。
    缺点:内存利用率低(默认新生代 Eden:S0:S1=8:1:1)。

  3. 标记-整理(Mark-Compact)
    步骤:标记存活对象后,向一端移动并清理边界外内存。
    适用场景:老年代。

  4. 分代收集算法
    新生代:复制算法(对象存活率低)。
    老年代:标记-清除或标记-整理算法(对象存活率高)。


五、分代模型(新生代与老年代)

  1. 分代原因
    • 不同对象生命周期差异大,分代可优化回收效率。
    • 新生代对象存活时间短,适合高频回收;老年代对象存活时间长,低频回收。

  2. 对象晋升规则
    年龄计数器:对象每熬过一次Minor GC,年龄+1。
    阈值:默认15岁(可通过-XX:MaxTenuringThreshold调整)。
    动态年龄判定:若某年龄对象总大小超过Survivor区50%(-XX:TargetSurvivorRatio),则直接晋升。


六、垃圾收集器

  1. Serial收集器
    特点:单线程,STW(Stop-The-World)时间长。
    适用场景:Client模式、小内存应用。

  2. ParNew收集器
    特点:Serial的多线程版本,与CMS配合使用。

  3. Parallel Scavenge/Old收集器
    特点:关注吞吐量(CPU利用率),适合后台计算任务。

  4. CMS(Concurrent Mark Sweep)
    步骤:初始标记(STW)→并发标记→重新标记(STW)→并发清除。
    优点:低停顿。
    缺点:内存碎片、CPU敏感。
    淘汰:JDK9后标记为过时,JDK14移除。

  5. G1(Garbage-First)
    特点
    ◦ 将堆划分为多个Region(默认2048个),优先回收价值高的Region。
    ◦ 可预测停顿时间(-XX:MaxGCPauseMillis)。
    步骤:初始标记→并发标记→最终标记→筛选回收。
    适用场景:大内存、低延迟要求(JDK9后默认)。

  6. ZGC
    特点:亚毫秒级停顿,支持16TB堆内存(JDK15正式可用)。


七、GC类型与触发条件

  1. Minor GC
    区域:新生代(Eden区满时触发)。
    特点:高频、快速。

  2. Full GC
    区域:整个堆(包括老年代、方法区)。
    触发条件
    ◦ 老年代空间不足。
    ◦ 方法区(元空间)不足。
    ◦ 空间分配担保失败(老年代连续空间不足)。


八、调优与监控

  1. 参数调优
    -Xms/-Xmx:初始堆/最大堆大小。
    -XX:NewRatio:新生代与老年代比例。
    -XX:SurvivorRatio:Eden区与Survivor区比例。

  2. 工具
    jstat:监控GC状态。
    jmap:堆内存分析。
    VisualVM:图形化监控。


九、关键总结

分代模型:优化回收效率,不同区域采用不同算法。
引用类型:强引用不回收,软/弱引用根据内存压力回收,虚引用跟踪回收。
收集器选择
• 低延迟:G1、ZGC。
• 高吞吐:Parallel Scavenge/Old。
Full GC避免:合理分配内存,避免大对象直接进入老年代,监控元空间使用。

通过理解上述机制,可有效解决内存溢出问题,优化JVM性能。

© 2019 - 2025 Lin 的博客

Powered by Hugo with theme Dream.

avatar
关于我

Lin 的 ❤️ 博客

记录一些 🌈 生活上,技术上的事

职业是JAVA全栈工程师