应用内存过大导致OOM

private_other 内存过大导致OOM
App 主要跑人工智能模型(大模型权重 / 大量 mmap / GPU/NPU buffer / native heap)
目标是 降低 private_other(mmap/anon/ion)占用、避免 OOM、并提升模型加载与推理稳定性
内存图像
cat proc/meminfo
MemTotal: 7848664 kB
MemFree: 4311224 kB
MemAvailable: 5675652 kB
Buffers: 3656 kB
Cached: 2121248 kB
SwapCached: 0 kB
Active: 301268 kB
Inactive: 1825472 kB
Active(anon): 3476 kB
Inactive(anon): 745896 kB
Active(file): 297792 kB
Inactive(file): 1079576 kB
Unevictable: 738256 kB
Mlocked: 116116 kB
SwapTotal: 3924328 kB
SwapFree: 3924328 kB
Dirty: 356 kB
Writeback: 0 kB
AnonPages: 740152 kB
Mapped: 1232804 kB // 此项很大
Shmem: 632164 kB
KReclaimable: 95560 kB
Slab: 169460 kB
SReclaimable: 62016 kB
SUnreclaim: 107444 kB
KernelStack: 18992 kB
ShadowCallStack: 4780 kB
PageTables: 43052 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 7848660 kB
Committed_AS: 50405152 kB
VmallocTotal: 262930368 kB
VmallocUsed: 53384 kB
VmallocChunk: 0 kB
Percpu: 7648 kB
CmaTotal: 131072 kB
CmaAllocated: 4160 kB
CmaReleased: 126912 kB
CmaFree: 126912 kB
OOM 根本原因:
- App private_other 占用很高 → 大量 mmap/anonymouse mapping
- Mapped 1.18 GB + Shmem 617 MB → 总地址空间分布碎片化
- Linux max_map_count=65530 限制 → mmap 太多会导致 ENOMEM
dumpsys meminfo
>dumpsys meminfo com.rockchip.gpadc.common
Applications Memory Usage (in Kilobytes):
Uptime: 90646583 Realtime: 90646583
** MEMINFO in pid 2612 [com.rockchip.gpadc.common] **
Pss Private Private Swap Rss Heap Heap Heap
Total Dirty Clean Dirty Total Size Alloc Free
------ ------ ------ ------ ------ ------ ------ ------
Native Heap 139712 139260 0 0 141572 174164 0 18365
Dalvik Heap 29830 28248 0 0 36212 22775 11388 11387
Dalvik Other 4910 2216 0 0 8620
Stack 4121 4120 0 0 4132
Ashmem 145 80 0 0 848
Other dev 622176 510908 111268 0 622460
.so mmap 25405 252 11672 0 56288
.jar mmap 1618 0 0 0 27000
.apk mmap 28744 2488 25840 0 31100
.ttf mmap 103 0 0 0 388
.dex mmap 18772 4 18728 0 19188
.oat mmap 3682 0 448 0 12432
.art mmap 3648 852 0 0 14816
Other mmap 1799 8 472 0 6128
Unknown 2093 2004 0 0 2528
TOTAL 886758 690440 168428 0 983712 196939 11388 29752
App Summary
Pss(KB) Rss(KB)
------ ------
Java Heap: 29100 51028
Native Heap: 139260 141572
Code: 59432 151344
Stack: 4120 4132
Graphics: 0 0
Private Other: 626956
System: 27890
Unknown: 635636
TOTAL PSS: 886758 TOTAL RSS: 983712 TOTAL SWAP (KB): 0
Objects
Views: 30 ViewRootImpl: 2
AppContexts: 8 Activities: 3
Assets: 8 AssetManagers: 0
Local Binders: 15 Proxy Binders: 39
Parcel memory: 9 Parcel count: 38
Death Recipients: 1 OpenSSL Sockets: 0
WebViews: 0
SQL
MEMORY_USED: 68
PAGECACHE_OVERFLOW: 12 MALLOC_SIZE: 46
DATABASES
pgsz dbsz Lookaside(b) cache Dbname
4 24 17 0/15/1 /storage/emulated/0/xintian-sort/db/sort.db
sys.lmk.minfree_levels
这个参数控制 lmkd 在不同内存压力下会杀死哪些优先级的进程
[sys.lmk.minfree_levels]: [18432:0,23040:100,27648:200,32256:250,55296:900,80640:950]
18432:0 → 可用 RAM < 72 MB → 允许杀 adj ≥ 0(实际不会杀前台)
23040:100 → 可用 RAM < 90 MB → 杀 adj ≥ 100 的进程
27648:200 → 可用 RAM < 108 MB → 杀 adj ≥ 200
32256:250 → 可用 RAM < 126 MB → 杀 adj ≥ 250
55296:900 → 可用 RAM < 216 MB → 杀 adj ≥ 900
80640:950 → 可用 RAM < 315 MB → 杀 adj ≥ 950(缓存最弱进程)
设备是RK3588 8G 内存, 可用内存还有很多,而且应用是前台应用,因此不太可能是sys.lmk.minfree_levels触发导致的OOM
可能原因
你的 AI 应用超过了 Android 对单进程的最大内存限制,而不是系统整体内存不足
单个应用最多只能用约 3GB 左右的虚拟地址空间(64-bit 条件下)
| 类型 | 默认值 (64-bit) |
|---|---|
| Java 堆 | maxMemory() 约 512MB~1.5GB(取决于 dalvik props) |
| native heap (malloc) | 可达 3GB,但受 ASLR & VMA 限制 |
| private_other(mmap) | 多时容易导致 address-space OOM |
private_other 多通常说明你大量使用 mmap 加载模型。
为什么你 private_other 很高却 OOM?
因为 mmap 数量过多 → VMA 数过多 → 触发 OOM:
- Android 和 Linux 默认 max_map_count = 65530
- 大模型(如 500MB+),如果分成几百个文件页映射,会很容易接近极限
解决方案-永久扩大进程 mmap 限制
device/rockchip/common/init.rk3588.rc
write /proc/sys/vm/max_map_count 262144
- write /proc/sys/vm/max_map_count 262144 → 可以暂时缓解 OOM
- 但单独做这一步不能根治,真正可靠的方法是 合并 mmap + buffer pool
RK3568 单个应用启动速度优化
| 属性 | 触发时机 | 当前值 | 含义 / 作用 | 优点 | 缺点 / 注意事项 |
|---|---|---|---|---|---|
pm.dexopt.ab-ota |
A/B OTA 分区切换后优化 | speed-profile |
对 OTA 后的应用/系统库进行 profile-guided AOT 优化 | 安装后热点代码快速可用,平衡 OTA 时间与性能 | 如果想最快启动可改为 speed,会增加 OTA 优化时间 |
pm.dexopt.bg-dexopt |
系统空闲时后台优化 | speed-profile |
后台 profile-guided dexopt,优先优化热点代码 | 逐步优化,降低首次启动延迟,CPU 占用温和 | 全量 speed 可更激进,但后台会占用更多资源 |
pm.dexopt.boot |
系统每次启动 | verify |
引导阶段只做 dex 验证,不做完整 AOT | 启动快,开机延迟低 | 运行时仍依赖 JIT,启动流畅度有限 |
pm.dexopt.first-boot |
系统或应用首次引导 | quicken |
轻量 quickening 优化,提高首次运行性能 | 首次体验比 verify 流畅,安装延迟小 |
不如全 AOT 快,长期性能需后台补充 |
pm.dexopt.inactive |
对长时间未使用的包 | verify |
对 inactive 包只做验证 | 节省存储和安装/优化时间 | 包再次使用时仍需 JIT 或后台优化 |
pm.dexopt.install |
APK 安装时 | speed-profile |
安装时对热点 dex 做 AOT,其他由 JIT | 安装速度适中,常用代码优化好 | 全量 speed 可更快运行,但安装耗时和存储占用增加 |
pm.dexopt.shared |
共享库 / 被多个用户或进程共享的 dex | speed |
对共享 dex 做完整 AOT | 多进程启动快,系统级共享库性能高 | 占用更多存储和安装时间 |
最小影响的修改方式
diff --git a/build/make/target/product/runtime_libart.mk b/build/make/target/product/runtime_libart.mk
index 693b686fbb..ec90d9d59c 100644
--- a/build/make/target/product/runtime_libart.mk
+++ b/build/make/target/product/runtime_libart.mk
@@ -68,9 +68,10 @@ endif
# The install filter is speed-profile in order to enable the use of
# profiles from the dex metadata files. Note that if a profile is not provided
# or if it is empty speed-profile is equivalent to (quicken + empty app image).
+# modify by lixiaogang for app start speed
PRODUCT_SYSTEM_DEFAULT_PROPERTIES += \
- pm.dexopt.install=speed-profile \
- pm.dexopt.bg-dexopt=speed-profile \
+ pm.dexopt.install=speed \
+ pm.dexopt.bg-dexopt=speed \
pm.dexopt.ab-ota=speed-profile \
pm.dexopt.inactive=verify \
pm.dexopt.shared=speed