自动垃圾回收机制

Java 的 自动垃圾回收机制(Garbage Collection, GC) 是 JVM 的核心能力之一,它负责自动管理内存,释放不再使用的对象,避免内存泄漏,让开发者不用手动释放内存(不像 C/C++)。

一、为什么需要垃圾回收?

  • Java 中使用 new 创建的对象存储在 堆内存
  • 程序运行过程中,有些对象不再使用(没有引用指向)
  • 如果这些对象不释放,内存就会被浪费,最终导致 内存泄漏内存溢出(OutOfMemoryError)
  • 为了解决这个问题,Java 提供了 自动垃圾回收机制

二、判断对象是否“垃圾”(是否还在使用)

GC 要决定哪些对象是“活”的,哪些可以回收,主要有两种方式:

1. 引用计数法(已废弃)

  • 每个对象维护一个引用计数,引用+1,释放-1
  • 计数为 0 就可以回收
  • 缺陷:无法处理循环引用

2. 可达性分析(Reachability Analysis)✅ 主流方法

  • 以一组称为“GC Roots”的对象为起点(如栈中的变量、静态变量等)
  • 从这些根开始,向下遍历所有可达的对象
  • 如果一个对象无法被 GC Roots 访问到,就认为是“不可达” → 说明它是垃圾

三、垃圾回收区域:内存结构

Java 的堆内存分为:

堆(Heap)
├── 新生代(Young Generation)
│   ├── Eden 区:新对象先放这里
│   └── Survivor 区(S0/S1):幸存者区,用于复制/清理
└── 老年代(Old Generation):长期存活对象

还有:

  • 方法区(元空间 Metaspace):类的元信息
  • 栈内存:线程私有,不参与 GC

四、垃圾回收过程(以 HotSpot 虚拟机为例)

1. Minor GC(针对新生代)

  • 回收频繁,速度快
  • 大多数对象是“朝生暮死”的 → Eden 区满了就触发 Minor GC
  • 存活的对象复制到 Survivor 区,经过多次 GC 后晋升到老年代

2. Major GC / Full GC(针对老年代/整个堆)

  • 回收老年代和整个堆
  • 触发条件:老年代满了、调用 System.gc()、元空间满了等
  • 执行代价高,可能会造成 STW(Stop-The-World)

五、GC 收集器(策略不同)

Java 提供了多种 GC 算法和收集器,例如:

收集器 特点 使用场景
Serial 单线程、STW,适合单核嵌入式系统 小程序/单线程环境
ParNew 多线程版本的 Serial 老牌并发收集器
G1(主流) 分区式管理、预测性 GC、低延迟 大内存应用,默认收集器(Java 9+)
CMS(已废弃) 并发标记清除,低延迟 Web 应用(旧版本常用)
ZGC / Shenandoah 超低延迟、支持大内存 大型服务端、云原生应用

六、什么时候会发生 GC?

  • 内存不足(Eden 或老年代满)
  • 手动调用System.gc()(仅建议 JVM 参考)
  • 大对象直接进入老年代(如大量数组)
  • 永久代/元空间溢出(类太多)

七、GC 日志 & 调优

可以通过 JVM 参数打印 GC 日志:

-XX:+PrintGCDetails
-XX:+PrintGCDateStamps

并可以设置最大堆、年轻代大小等:

-Xmx1024m -Xms1024m -Xmn512m

总结一句话:

Java 的垃圾回收机制是 JVM 帮我们自动释放内存的能力,它通过可达性分析判断对象是否“死掉”,并通过不同的GC 算法完成回收,解决了内存泄漏、悬挂指针等传统问题,大大降低了开发复杂度,是 Java 高可靠性的基础保障。


⬅️ AOT 编译 🏠 00-Java ➡️ 内存泄漏