简单说一下java 垃圾处理器回收机制

39 阅读2分钟

1) 基本概念

  • 可达性分析:从 GC Roots(线程栈、本地变量、静态字段、JNI 全局等)出发能“走到”的对象为存活

  • Stop-The-World(STW):GC 的关键阶段会暂停所有业务线程(在安全点)。

  • 算法三件套

    • 标记-清除:标出存活 → 清掉其余(会产生碎片)。

    • 标记-整理:标记后把活对象压缩到一侧(无碎片)。

    • 复制:从“from”区拷到“to”区(快、无碎片,需额外空间)。

2) 分代回收(Generational GC,默认思路)

经验:大多数对象很快死,少数活得久。

  • 堆分代新生代(Eden + 两个 Survivor)和老年代

  • 新生代回收(Minor/Young GC)

    1. 大量对象分配在 Eden
    2. 触发 Young GC 时,用复制算法把存活对象从 Eden/S0 → S1;
    3. 多次“幸存”后(达年龄阈值)晋升到老年代
  • 老年代回收(Major/Old/Full GC) :对象多、内存大,通常用标记-整理分区化转移,停顿更长。

  • 触发场景:空间不足、晋升失败、System.gc()、元空间/大对象压力等。

3) 主流收集器(JDK 11+/17+)

  • G1(默认) :把堆拆成很多Region,按需回收;

    • Young GC:回收年轻 Region(复制算法);
    • 并发标记:后台标活;
    • Mixed GC:同时回收部分老年代 Region;
    • 目标:可预测的短停顿(可设 -XX:MaxGCPauseMillis=)。
  • ZGC / Shenandoah低停顿(ms 级),大堆友好;

    • 并发标记 + 并发转移(着色指针/读屏障);
    • 代价是更复杂的屏障与少量吞吐损失。
  • (历史)Parallel/Serial:吞吐优先或小堆;CMS 已移除(JDK14)。

4) 写屏障/记忆集 & 跨代指针

  • 为了让“年轻代回收”不扫描整个老年代,使用卡表/记忆集记录“老 → 新”的引用;写字段时通过写屏障打脏卡,提高回收效率。

5) 引用类型与回收顺序(简记)

强引用 > 软引用 > 弱引用 > 虚引用

  • 软引用:内存吃紧会清;

  • 弱引用:下一次 GC 清;

  • 虚引用:仅用于“临终通知”(配 ReferenceQueue)。

6) 你能用到的调参/观测

  • 大小:-Xms/-Xmx(堆)、-XX:MaxMetaspaceSize(元空间)

  • 收集器:-XX:+UseG1GC(默认)、-XX:+UseZGC、-XX:+UseShenandoahGC

  • 目标:-XX:MaxGCPauseMillis=200(G1 目标停顿)

  • 日志:-Xlog:gc*,safepoint(JDK9+)——看触发原因、停顿、晋升失败等。

7) 常见问题速记

  • 频繁 Minor GC:Eden 太小/对象分配过猛 → 调大年轻代或优化短命对象创建。
  • 晋升失败 / Full GC:老年代/Region 不足 → 降低对象长寿、减少大对象、增大堆或优化内存复用。
  • 碎片:标记-清除易碎片;G1/ZGC 通过转移/整理缓解。
  • finalize 已废弃:用 Cleaner/PhantomReference 或显式 close()。

一句话:Java GC 通过“可达性分析 + 分代回收(新生代复制,老年代标记整理)”,在必要时 STW,现代收集器(G1/ZGC/Shenandoah)用并发标记/转移记忆集把停顿控制在可接受范围。