JVM-垃圾回收

一、先搞懂:JVM 为啥要做垃圾回收?

简单说,Java 程序运行时会在 JVM 堆内存里创建大量对象(比如new User()),那些不再被任何引用指向的对象就是 “垃圾”,如果不清理,内存会被占满导致程序崩溃。垃圾回收的核心目标:自动识别并清理堆中无用对象,释放内存,避免内存泄漏 / 溢出,不用像 C++ 那样手动free/delete

二、核心基础:怎么判断对象是 “垃圾”?

这是 GC 的第一步,常用 2 种方法:

1. 引用计数法(简单但有缺陷)

  • 逻辑:给每个对象加一个 “引用计数器”,有引用指向它就 + 1,引用断开就 - 1;计数器为 0 就是垃圾。
  • 坑:无法解决循环引用(比如 A 引用 B,B 引用 A,两者都没用但计数器都不为 0),JVM 实际不用这种方法。

2. 可达性分析算法(JVM 主流)

  • 逻辑:以 “GC Roots” 为起点(比如虚拟机栈里的局部变量、静态变量、JNI 引用等),向下遍历引用链;没有被连接到的对象就是垃圾。
  • 举个栗子:
    java
     
    运行
     
     
     
     
    public void test() {
        User u1 = new User(); // u1是GC Roots(局部变量),User对象可达,不是垃圾
        u1 = null; // 引用断开,User对象不可达,标记为垃圾
        User u2 = new User(); 
        User u3 = u2; 
        u2 = null; // u3还引用User对象,仍可达,不是垃圾
    }
     
     

三、垃圾回收的 “核心动作”:分代回收(堆内存分区)

JVM 把堆分成 “新生代” 和 “老年代”,因为不同对象的生命周期不同,用不同策略回收更高效:
区域 特点 回收策略 核心回收器
新生代 对象创建快、死亡快(90% 对象短命) 频繁 Minor GC(轻量回收) Serial/ParNew/Parallel Scavenge
老年代 存活久的对象(从新生代存活下来) 低频 Major GC/Full GC(重量级) CMS/G1/ZGC/Shenandoah

关键流程(以最经典的 “复制算法” 为例):

新生代又分 1 个 Eden 区 + 2 个 Survivor 区(S0/S1):
  1. 新对象先放 Eden 区,Eden 满了触发 Minor GC,存活对象复制到 S0,清空 Eden;
  2. 下次 Minor GC,Eden+S0 的存活对象复制到 S1,清空 Eden+S0;
  3. 反复几次后,还存活的对象 “晋升” 到老年代;
  4. 老年代满了触发 Major GC/Full GC,清理老年代垃圾(耗时久,会导致程序卡顿)。

四、常见垃圾回收器(新手必知)

不同回收器适配不同场景,核心看 “吞吐量” 和 “停顿时间”:

1. Serial GC(串行回收器)

  • 单线程回收,只适合单核 / 小内存场景(比如桌面程序、嵌入式),优点是简单、内存占用少,缺点是停顿久。

2. Parallel Scavenge(并行回收器)

  • 多线程回收新生代,追求 “高吞吐量”(运行程序时间 / 总时间),适合后台计算型程序(比如大数据处理),默认 JDK8 的新生代回收器。

3. CMS(并发标记清除)

  • 老年代回收器,主打 “低停顿”(用户几乎感知不到 GC),分 4 步:初始标记→并发标记→重新标记→并发清除;
  • 缺点:会产生内存碎片,占用 CPU 资源,JDK9 开始被标记为废弃。

4. G1 GC(Garbage First)

  • JDK9 默认回收器,把堆分成多个小块,优先回收垃圾多的块,兼顾吞吐量和停顿时间,适合大内存场景(比如 8G 以上堆),是目前主流。

五、新手常见误区

  1. 误区 1:GC 会回收所有无用对象 → 错!GC 只能回收堆内存的对象,栈、方法区的资源(比如线程、静态变量)管不了;
  2. 误区 2:Full GC 是手动调用System.gc()触发的 → 错!System.gc()只是 “建议” JVM 回收,JVM 可以忽略;Full GC 通常是老年代满、永久代 / 元空间满等触发;
  3. 误区 3:GC 停顿越短越好 → 错!要平衡:比如实时系统(电商支付)要低停顿,后台计算要高吞吐量。

总结

  1. JVM 垃圾回收核心是识别无用对象(可达性分析)+ 分代清理(新生代 / 老年代),避免手动管理内存;
  2. 判断垃圾的核心算法是可达性分析,而非引用计数(解决循环引用问题);
  3. 常见回收器各有侧重:Serial(单核)、Parallel(吞吐量)、CMS(低停顿)、G1(兼顾),实际开发中 G1 是主流选择。
posted @ 2025-12-23 16:03  爱吃牛腩  阅读(0)  评论(0)    收藏  举报