ART 内存模型与对象布局
2026/8/30大约 4 分钟
ART 内存模型与对象布局
面试高频指数:高 ART 的内存模型决定了对象分配、GC 与内存优化的行为。理解对象布局有助于排查内存问题与优化分配。
1. ART 内存模型总览
ART 内存模型:
① Java 堆(Heap):对象分配主区域
② 非堆:类元数据、编译产物、JIT 代码
③ 本机内存:Bitmap(部分)、JNI 分配
分区:
- Main space(主空间,对象长期存活)
- Non-moving space(非移动空间,类对象等)
- Image space(镜像空间,启动预加载)
- Zygote space(Zygote 预分配)
- Large object space(大对象空间,> 阈值)| 空间 | 特点 | 存放内容 |
|---|---|---|
| Zygote space | Zygote 预分配 | 系统类对象 |
| Image space | 只读镜像 | 预编译类、字符串 |
| Main space | 可压缩 | 普通对象 |
| Non-moving space | 不可移动 | 类、数组锁等 |
| Large object space | 单独管理 | 大数组、Bitmap 底层 |
2. 对象布局(Object Layout)
2.1 对象头(Object Header)
ART 对象头部(32/64 位不同):
- mark word(锁状态、GC 信息)
- klass pointer(类引用)
示例(64 位):
| lock word (32bit) | klass (32bit) | 字段数据... || 头部字段 | 作用 |
|---|---|
| lock word | 偏向锁/轻量锁/重量锁状态、GC age |
| klass | 指向 Class 对象(反射、方法查找) |
2.2 字段布局
对象字段布局规则:
- 引用类型字段(4/8 字节,按压缩引用模式)
- 基本类型按对齐规则排列
- 字段顺序经过排列优化(减少填充)
字段对齐:
- 对象整体 8 字节对齐(64 位)
- 数组:头部 + 长度 + 元素
压缩引用(compressed reference):
- 默认开启(Android 5.0+)
- 引用为 32 位索引(指向对象池),省一半引用内存
- 4GB 以上堆需关闭(应用默认开启)3. 引用类型与 GC
3.1 四种引用
| 引用类型 | 回收时机 | 用途 |
|---|---|---|
| 强引用 | 永不(除非不可达) | 默认 |
| SoftReference | 内存不足时 | 缓存(图片内存缓存) |
| WeakReference | 下一次 GC | 观察者、Handler 持有 |
| PhantomReference | 对象回收后 | 资源清理(Cleaner) |
3.2 GC Roots
GC Roots(根集合):
① 栈上引用(局部变量、参数)
② 静态字段(类静态变量)
③ JNI 全局引用(GlobalRef)
④ 运行时常量池引用
⑤ 活跃线程(Thread 对象)
可达性分析:
从 Roots 出发遍历引用图,
不可达对象 → 可回收4. 对象分配路径
4.1 分配流程
new Object()
→ ART 分配器(Allocator)
→ 线程本地缓冲区(Thread Local Allocation Buffer, TLAB)
→ 未满 → 快速分配(无锁)
→ TLAB 满 → 申请新缓冲区(慢路径)
→ 堆满 → 触发 GC → 重试分配
→ 仍失败 → OOM4.2 分配器类型
| 分配器 | 适用空间 | 特点 |
|---|---|---|
| Bump pointer | 可压缩空间 | 快速,只移动指针 |
| Free list | 非移动空间 | 空闲链表 |
| Rosalloc | 主空间 | 按大小分级,减少碎片 |
| Large object | 大对象空间 | 页对齐分配 |
5. 内存对齐与缓存行
对齐的意义:
- 对象 8 字节对齐 → CPU 高效访问
- 避免 false sharing(多线程访问同一缓存行)
- 减少 padding 浪费
字段排序优化:
- ART 会重排字段减少 padding
- 但受限于 Java 内存模型可见性约束
- 反射顺序可能与声明顺序不同(不保证)6. 内存优化实践
6.1 常见问题
| 问题 | 原因 | 优化 |
|---|---|---|
| 内存抖动 | 频繁分配短命对象 | 复用对象、对象池 |
| 内存泄漏 | 长生命周期持有短对象 | 弱引用、及时清理 |
| 大对象 | Bitmap、大数组 | 压缩、采样、复用 |
| 碎片 | 反复分配/释放 | 压缩 GC、减少抖动 |
6.2 Bitmap 内存
Bitmap 内存模型(8.0+):
- 像素数据在 Java 堆(native 分配但计入堆统计)
- 采样加载(inSampleSize)
- 复用(inBitmap)
注意:大图直接 OOM 是高频事故,
务必做尺寸裁剪与密度适配。7. 高频面试题
Q1:ART 的对象头包含什么? A:lock word(锁状态、GC age)与 klass(类引用)。64 位下头部约 8-16 字节,压缩引用模式引用为 32 位。
Q2:压缩引用是什么? A:对象引用以 32 位索引替代 64 位指针,指向对象池,减少约一半引用内存。Android 5.0+ 默认开启,大堆需关闭。
Q3:GC Roots 有哪些? A:栈引用、静态字段、JNI 全局引用、常量池引用、活跃线程。可达性分析从 Roots 遍历,不可达即回收。
Q4:对象分配为什么会 OOM? A:TLAB 分配失败 → 堆满 → GC 回收后仍不足 → OOM。常见原因:大对象(Bitmap)、内存泄漏(不可达但被持有)、堆上限小。
Q5:内存抖动为什么卡顿? A:频繁分配/回收触发 GC,GC 暂停(STW)与回收开销导致掉帧。优化:复用对象、减少临时分配、使用对象池。
8. 小结
- ART 堆分多空间:Zygote/Image/Main/Large object 等。
- 对象布局:头部(锁+类)+ 字段(压缩引用、对齐)。
- GC Roots 可达性分析决定对象生死。
- TLAB 快速分配,失败走慢路径 → GC → OOM。
- 内存优化:防抖动、防泄漏、控大对象。