--- title: "00-自动垃圾回收机制" created: 2025-12-02 tags: - Java --- # 自动垃圾回收机制 Java 的 **自动垃圾回收机制(Garbage Collection, GC)** 是 JVM 的核心能力之一,它负责**自动管理内存**,释放不再使用的对象,避免内存泄漏,让开发者不用手动释放内存(不像 C/C++)。 ## 一、为什么需要垃圾回收? - Java 中使用 `new` 创建的对象存储在 **堆内存** 中 - 程序运行过程中,有些对象不再使用(没有引用指向) - 如果这些对象不释放,内存就会被浪费,最终导致 [[01-内存泄漏|内存泄漏]] 或 [[02-内存溢出|内存溢出]]**(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 高可靠性的基础保障。 --- ⬅️ [[04-AOT编译|AOT 编译]] 🏠 [[00-Java|00-Java]] ➡️ [[01-内存泄漏|内存泄漏]]