ART 堆与 GC:Java 内存如何被管理
2026/8/9大约 4 分钟进程与内存管理Android 14ARTGC堆内存
ART 堆与 GC:Java 内存如何被管理
上一章看了进程创建。这一章回答:应用的 Java 对象存在哪,堆大小怎么定,GC 何时触发, OutOfMemoryError 从哪来?
应用抛出 OutOfMemoryError 时,常见原因是 ART 无法在当前堆增长上限内满足分配,而不是 整台设备已经没有可用页。GC、堆上限、native 分配和系统压力需要分开观察。
Java 堆 OOM 不等于设备耗尽内存
| 常见误解 | 正确理解 |
|---|---|
| OOM 一定是内存真的用完了 | 通常是达到进程堆上限,物理内存可能还够 |
| largeHeap=true 就能无限要内存 | 只是提高堆上限,仍受设备内存与系统限制 |
| GC 越频繁越好 | GC 有开销,频繁 GC 会带来卡顿,要平衡 |
核心结论
- 堆上限由设备内存档位决定,应用可申请 largeHeap 提高上限。
- GC 在分配压力、内存阈值与系统低内存信号下触发。
- OOM 通常来自堆上限,而不是物理内存耗尽。
- 系统低内存时,ART 会收到通知做堆整理(trim),配合整体回收。
- 排查顺序:先看堆用量与上限,再看泄漏,最后才怀疑设备内存。
堆管理与 GC 主链
逐步解释:
- 分配:应用 new 对象,ART 从堆中分配。
- 增长:堆用量上升,接近上限时分配压力增大。
- GC:回收无引用对象;压力继续则触发更激进回收。
- OOM:回收后仍无法满足分配,抛出 OutOfMemoryError。
- 系统协作:设备内存档位定上限,低内存信号触发堆整理。
largeHeap 为什么不是万能药
android:largeHeap="true" 只提高堆上限,不增加设备物理内存。堆开得越大,GC 压力与 卡顿风险越高,还可能更快触发系统低内存回收。优化方向永远是“减少占用”,而不是 “扩大货仓”。
源码证据
阅读目标:确认堆配置来源与 OOM 路径。
正文指针:ActivityManager.java 中堆内存信息(getMemoryInfo()); Runtime.java maxMemory();ART 侧 art/runtime/gc/ 的堆管理。
// Runtime.java(伪代码,行号以 r75 为准)
public native long maxMemory(); // 当前堆上限
public native long totalMemory(); // 已申请堆这段代码证明: 堆上限对应用可见(maxMemory);OOM 的判定发生在 ART 分配失败且 GC 无法回收时,而不是设备内存耗尽时。
验证与排障
环境:开发设备或模拟器;以下命令不需要 root。
adb shell dumpsys meminfo <包名> | grep -E "Heap|dalvik"
adb shell am dumpheap <包名> /data/local/tmp/heap.hprof
adb logcat -v threadtime | grep -E "OutOfMemory|GC_|heap"dumpsys meminfo 看 Java/native 堆分配;am dumpheap 导出 hprof 分析泄漏; logcat 看 GC 与 OOM。OOM 先看堆上限与分配峰值,再看泄漏点,不要直接怀疑设备内存。
常见误区
- “OOM 就是内存不足”:多数是堆上限问题。
- “largeHeap 能根治内存问题”:只是提高上限,增加 GC 与卡顿风险。
- “GC 越多越好”:GC 有开销,卡顿常与频繁 GC 相关。
- “只看 Java 堆就行”:native 内存泄漏同样会导致系统级低内存。
延伸问题
- Android 14 默认 GC 与老版本有什么区别?
getMemoryClass()与getLargeMemoryClass()分别代表什么?- native 内存与 Java 堆如何相互影响?
- 系统低内存时,ART 的堆整理机制如何工作?
源码入口
| 文件 | 关键位置 | 作用 |
|---|---|---|
Runtime.java | maxMemory() | 堆上限 |
ActivityManager.java | getMemoryClass() | 设备档位 |
art/runtime/gc/ | 堆与回收 | GC 实现 |
dumpsys meminfo | 内存报告 | 排障入口 |
公共路径:frameworks/base/core/java/android/os/ 与 art/runtime/。行号以 r75 检索为准。
系统整体紧张时应用会收到什么信号,见 内存压力与回收。