核心定位
- 主要 & 最频繁 GC:集中于堆内存。
对象回收判断机制
-
引用计数法
- 逻辑:引用存在则+1,消失则-1;计数为0则回收。
- 缺陷:循环引用(如A→B, B→A)导致计数永不归零 → 内存泄漏(分配内存后无法回收,持续增长)。
- Java未采用此法。
-
可达性分析(主流)
- GC Root(不可回收对象起点):
- 系统类(如启动类加载器加载的类)
- Native Stack(JNI调用产生的对象)
- Synchronized Monitor(锁对象)
- 活动线程(正在运行的线程栈帧)
- 过程:从GC Root遍历引用链,未触及对象 → 可回收。
- GC Root(不可回收对象起点):
四种引用
| 类型 | 特性 | 应用场景 |
|---|---|---|
| 强引用 | 默认(Object obj = new Object());存在即永不回收(OOM前不回收)。 | 一般对象 |
| 软引用 | 无强引用时,内存不足时回收;配合引用队列。 | 内存敏感缓存(如LruCache) |
| 弱引用 | 无强引用时,下一次GC即回收;配合引用队列。 | WeakHashMap(防内存泄漏) |
| 虚引用 | 必须配引用队列;get()返回null;仅用于回收前通知(如ByteBuffer)。 | 对象回收监听(如资源清理) |
终结器引用(Finalizer)
- 重写
finalize()→ 对象不立即回收,先加入Finalizer Queue,由后台线程调用finalize()。- ⚠️ 注意:
finalize()中重建强引用 → 对象“复活”(本次不回收)。- 不保证执行(JVM退出前未触发GC则失效)。
- Java 9+ 已废弃(推荐
Cleaner或try-with-resources)。
垃圾回收算法
| 算法 | 过程 | 缺点 |
|---|---|---|
| 标记-清除 | 标记未引用对象 → 清理(仅记录地址,不移动内存)。 | 产生内存碎片 |
| 标记-整理 | 标记未引用对象 → 移动存活对象至一端,压缩内存。 | 移动地址 → 效率低 |
| 复制 | 分From/To两区;存活对象移To区 → 清空From区 → 交换From/To。 | 占用双倍内存 |
分代回收机制
-
新生代(生命周期短,高频GC)
- 伊甸园(Eden):新对象分配处;满 → 触发Minor GC(STW暂停用户线程)。
- 幸存者区(From/To):
- Minor GC后存活对象 → 移To区,年龄+1;
- From区无回收 → 交换From/To,年龄+1。
- 晋升条件:对象年龄≥15(默认阈值)→ 晋升老年代。
- 大对象:直接分配至老年代(若新生代空间不足)。
-
老年代(生命周期长,低频GC)
- Minor GC后空间不足 → 触发Full GC(STW时间更长,清理新生代+老年代)。
- 注:Full GC后仍不足 → 抛
OutOfMemoryError(单线程异常不导致JVM退出)。
垃圾回收器
| 类型 | 特点 | 适用场景 |
|---|---|---|
| 串行回收器 | 单线程;STW期间暂停所有线程。 | 小内存(个人PC) |
| 吞吐量优先 | 多线程;最大化吞吐量(STW时间占比低)。 | 大内存(多核CPU) |
| 响应时间优先 | 多线程+并发(减少单次STW): - 初始标记(STW极短)→ 并发标记 → 重新标记(STW)→ 并发清理。 | 低延迟场景 |
关键:
- STW(Stop-The-World):GC期间暂停用户线程。
- 响应优先器:并发执行 → 降低延迟,但影响吞吐量。