自动垃圾回收机制
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 高可靠性的基础保障。
💬 评论