GC 垃圾回收机制
问题
Android ART 虚拟机的垃圾回收机制是怎样的?
答案
ART GC 策略
ART 使用分代回收 + 并发复制策略:
GC 类型
| GC 类型 | 触发条件 | STW 时间 |
|---|---|---|
| Young GC | 年轻代满 | < 1ms |
| Concurrent Copying | 堆使用率高 | ~1ms(仅标记根) |
| Full GC | 内存严重不足 | 较长(十几 ms) |
| Explicit GC | System.gc() | 较长 |
GC Root 类型
从 GC Root 出发不可达的对象才会被回收。
引用类型
// 强引用 —— 不会被 GC
val user = User()
// 软引用 —— 内存不足时回收(适合缓存)
val softRef = SoftReference(Bitmap())
// 弱引用 —— 下次 GC 就回收
val weakRef = WeakReference(activity)
// 虚引用 —— 随时回收,用于跟踪 GC
val phantomRef = PhantomReference(obj, queue)
常见面试问题
Q1: Android 8.0 前后 Bitmap 的内存分配有何变化?
答案:
| 版本 | Bitmap 像素数据 | 影响 |
|---|---|---|
| Android < 8.0 | Java Heap | 占用 Java 堆,容易 OOM |
| Android >= 8.0 | Native Heap | 不占 Java 堆,但仍占内存 |
8.0 后 Bitmap 使用 NativeAllocationRegistry 跟踪 Native 内存,GC 时一起释放。
Q2: 为什么不建议主动调用 System.gc()?
答案:
- ART 的 GC 已经非常高效,自动管理
System.gc()只是建议,不保证立即执行- 可能触发 Full GC,造成全局 STW 暂停
- 如果频繁调用,反而影响性能
Q3: Finalizer 的问题是什么?
答案:
重写 finalize() 的对象需要至少两次 GC 才能回收(第一次标记放入 Finalizer 队列,执行 finalize() 后第二次才回收),且 Finalizer 线程优先级低可能积压。现代 Android 推荐使用 Cleaner 或 PhantomReference。