![图片[1]-JVM垃圾回收机制(上):GC算法与内存管理-速优课](http://www.suyouke.com/wp-content/uploads/2026/07/doubao_img_2304x1728_20260722_174942-1-1024x768.png)
垃圾回收(GC)是 JVM 自动内存管理的核心机制,它自动回收不再使用的对象,避免内存泄漏。本文将深入探讨垃圾回收的基本原理、常用算法以及内存管理策略。
一、垃圾回收的基本概念
什么是垃圾
垃圾是指不再被任何引用指向的对象。这些对象占用的内存可以被回收,供新对象使用。
垃圾回收的目标
- 回收无用对象:释放不再使用的内存
- 减少内存碎片:整理内存空间,提高内存利用率
- 保证程序运行:避免内存溢出(OutOfMemoryError)
垃圾回收的挑战
- 如何判定对象是否存活:需要高效的可达性分析算法
- 如何高效回收内存:需要选择合适的回收算法
- 如何减少停顿时间:避免影响应用程序的响应性
二、对象存活判定算法
引用计数法
原理:为每个对象维护一个引用计数器,当引用增加时计数加 1,引用减少时计数减 1,计数为 0 时对象可回收。
优点:简单、高效
缺点:无法处理循环引用
// 循环引用示例
class Node {
Node next;
}
Node a = new Node();
Node b = new Node();
a.next = b;
b.next = a;
a = null;
b = null;
// 此时 a 和 b 的引用计数都不为 0,但它们都是垃圾
可达性分析法
原理:从 GC Roots 出发,遍历所有可达对象,不可达对象即为垃圾。
GC Roots 的种类:
| 类型 | 说明 |
|---|---|
| 虚拟机栈引用的对象 | 局部变量表中的引用 |
| 方法区中类静态属性引用的对象 | 静态变量 |
| 方法区中常量引用的对象 | 常量池中引用 |
| 本地方法栈引用的对象 | native 方法中的引用 |
可达性分析过程:
GC Roots
↓
对象A ← 对象B ← 对象C
↓
对象D(不可达,可回收)
Java 中的引用类型
Java 提供了四种引用类型,用于控制对象的生命周期:
| 引用类型 | 说明 | 垃圾回收时机 |
|---|---|---|
| 强引用 | 默认引用类型 | 永远不会被回收 |
| 软引用 | 内存不足时回收 | 抛出 OOM 前 |
| 弱引用 | 下次 GC 时回收 | 每次 GC |
| 虚引用 | 唯一目的是接收回收通知 | 随时回收 |
// 引用类型示例
String str = new String("hello"); // 强引用
SoftReference<String> softRef = new SoftReference<>(new String("soft"));
WeakReference<String> weakRef = new WeakReference<>(new String("weak"));
PhantomReference<String> phantomRef = new PhantomReference<>(
new String("phantom"), new ReferenceQueue<>());
三、垃圾回收算法
标记-清除算法
流程:
- 标记:遍历所有可达对象,标记为存活
- 清除:遍历堆内存,回收未标记的对象
优点:简单
缺点:
- 产生内存碎片
- 效率较低(需要两次遍历)
标记-复制算法
流程:
- 将堆内存分为两个相等的区域(From 区和 To 区)
- 只使用 From 区分配对象
- 垃圾回收时,将存活对象复制到 To 区
- 清空 From 区,交换两个区域的角色
优点:
- 无内存碎片
- 分配效率高(指针碰撞)
缺点:
- 内存利用率低(只有一半可用)
- 复制开销大
标记-整理算法
流程:
- 标记:遍历所有可达对象,标记为存活
- 整理:将存活对象向一端移动,然后清除边界外的内存
优点:
- 无内存碎片
- 内存利用率高
缺点:整理开销大
分代收集算法
结合以上三种算法,根据对象的生命周期分为不同代:
| 代 | 特点 | 回收算法 |
|---|---|---|
| 新生代 | 对象生命周期短,大量创建和回收 | 标记-复制 |
| 老年代 | 对象生命周期长,存活时间久 | 标记-清除/标记-整理 |
| 永久代/元空间 | 存储类元数据、常量池 | 标记-清除 |
四、垃圾回收器
串行回收器(Serial)
- 单线程回收:使用一条线程进行垃圾回收
- 适用于:客户端应用、单核 CPU
- 优点:简单、高效(无线程切换开销)
- 缺点:停顿时间长
并行回收器(Parallel)
- 多线程回收:使用多条线程进行垃圾回收
- 适用于:服务器端应用、多核 CPU
- 优点:回收速度快
- 缺点:停顿时间较长
CMS 回收器(Concurrent Mark Sweep)
- 并发回收:与应用线程并发执行
- 适用于:对响应时间要求高的应用
- 优点:停顿时间短
- 缺点:
- 内存碎片问题
- CPU 占用高
- 无法处理浮动垃圾
G1 回收器(Garbage First)
- 分区回收:将堆内存分为多个 Region
- 并发回收:与应用线程并发执行
- 可预测停顿:可以设置最大停顿时间
- 适用于:大堆内存(4GB+)
- 优点:
- 停顿时间可控
- 无内存碎片
- 效率高
ZGC 回收器(Z Garbage Collector)
- 低延迟回收:停顿时间不超过 10ms
- 适用于:超大堆内存(16GB+)
- 优点:极低延迟
- 缺点:吞吐量略低
五、垃圾回收的触发条件
新生代回收(Minor GC)
触发条件:
- Eden 区满时
- 新对象分配失败时
特点:
- 频率高
- 停顿时间短
老年代回收(Major GC/Full GC)
触发条件:
- 老年代空间不足时
- 永久代/元空间不足时
- 调用 System.gc() 时
特点:
- 频率低
- 停顿时间长
六、总结
垃圾回收是 JVM 的核心功能,涉及多个方面:
- 存活判定:引用计数法和可达性分析法
- 回收算法:标记-清除、标记-复制、标记-整理
- 分代收集:新生代使用复制算法,老年代使用清除/整理算法
- 垃圾回收器:Serial、Parallel、CMS、G1、ZGC
- 触发条件:Minor GC(Eden 区满)、Major GC(老年代满)
理解垃圾回收机制,对于编写高效代码和进行 JVM 调优至关重要。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END








请登录后查看评论内容