内存管理-31-系统内存统计-6-dumpsys meminfo-2-理论实现
一、dumpsys meminfo <pid> 的实现原理
下面基于你当前两套源码说明;Android 12 与 Android 14 的核心链路基本一致, 主要基于 Android 12 来说。
1. 整体调用链
adb shell dumpsys meminfo <pid> │ ▼ dumpsys 客户端查找 Binder 服务 "meminfo" //binder域中的有名服务 │ ▼ IBinder::dump(fd, args) │ ▼ system_server / ActivityManagerService.MemBinder │ ▼ AMS 根据 PID 查找 ProcessRecord │ ├─ Java/Android 应用进程 │ ├─ system_server 读取 /proc/<pid>/smaps │ ├─ 调用 memtrack 获取 GPU/GL 内存 │ └─ Binder 调用目标进程 IApplicationThread.dumpMemInfo() │ ├─ 获取 Native Heap allocator 信息 │ ├─ 执行一次 Runtime.gc() │ ├─ 获取 ART/Dalvik Heap 信息 │ ├─ 统计 View/Activity/Binder/SQLite 等对象 │ └─ 将结果写入 TransferPipe │ └─ Native 进程 ├─ system_server 读取 /proc/<pid>/smaps ├─ 调用 memtrack └─ system_server 本地格式化输出
因此,dumpsys meminfo <pid> 不是简单地打印 /proc/<pid>/status,而是将三类数据组合起来:
(1) 内核 /proc/<pid>/smaps;
(2) graphics memtrack HAL/驱动统计;
(3) 目标 Android 应用进程内部的 ART、malloc、对象和 SQLite 统计。
2. dumpsys 命令如何进入 meminfo 服务
2.1 dumpsys 查找 Binder 服务
实现位于:android\frameworks\native\cmds\dumpsys\dumpsys.cpp,dumpsys meminfo <pid> 中:meminfo 是 Binder service 名称;<pid> 是传给该服务的参数。
sp<IBinder> service = sm_->checkService(serviceName); int sfd[2]; pipe(sfd); activeThread_ = std::thread([=, remote_end{std::move(remote_end)}]() mutable { err = service->dump(remote_end.get(), args); });
工作方式是:
(1) 从 ServiceManager 查找 meminfo;
(2) 创建 pipe;
(3) 后台线程调用 IBinder::dump();
(4) Binder 服务把文本写到 pipe 写端;
(5) dumpsys 从读端转发到终端;
(6) dumpsys 自己负责超时控制。
所以这里没有直接读取进程内存,真正采集都在 system_server 中进行。
3. meminfo Binder 服务注册
服务由 AMS 注册:
//android\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java ServiceManager.addService("meminfo", new MemBinder(this), false, DUMP_FLAG_PRIORITY_HIGH);
Binder 实现是 ActivityManagerService.MemBinder,约 1965 行。
其 dump() 中主要做三件事:
mCachedAppOptimizer.enableFreezer(false); DumpUtils.checkDumpAndUsageStatsPermission(...); PriorityDump.dump(mPriorityDumper, fd, pw, args); mCachedAppOptimizer.enableFreezer(true);
含义:
(1) 临时关闭 cached app freezer,避免目标进程被冻结后无法响应 Binder;
(2) 检查 DUMP/usage stats 权限;
(3) 调用:dumpApplicationMemoryUsage(...)
(4) 完成后重新允许 freezer。
这也是为什么 shell/root 能执行,而普通应用不能随意读取所有进程的详细 meminfo。
4. 参数解析和进程选择
入口位于:android\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
4.1 支持的主要参数包括:
--------------------------------------------------------------------- 参数 作用 --------------------------------------------------------------------- -a 完整信息、完整分类、Dalvik 子分类和 SwapPss -d 显示 Dalvik/ART 详细分类 -s 只显示 App Summary -S 显示 SwapPss --local 只在 system_server 本地采集,不调用目标进程 --unreachable 扫描 native unreachable memory --oom 按 oom_adj 分组显示 --package 参数按 package 解析 --checkin 输出机器可解析的 CSV 格式 --proto 输出 protobuf ---------------------------------------------------------------------
随后调用:collectProcesses(...) 这个 Java 函数把 PID、进程名或包名转换为 ProcessRecord。
4.2 如果只指定一个 Android 应用 PID:
procs.size() == 1
AMS 会自动设置:opts.dumpDetails = true; 所以普通的:adb shell dumpsys meminfo <pid> 对 Java 应用来说,实际属于详细采集路径,不只是快速读取 PSS。
5. Java 应用进程的两阶段采集
单个应用进程主要分为两个阶段。
5.1 阶段 1:system_server 读取目标 PID 的 smaps
AMS 中:
//android\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java Debug.MemoryInfo mi = new Debug.MemoryInfo(); if (!Debug.getMemoryInfo(pid, mi)) { continue; }
这里发生在 system_server 中,它直接读取目标进程的:/proc/<pid>/smaps,并把结果填入 Debug.MemoryInfo。因此不需要目标应用主动配合,就能拿到:
PSS;
RSS;
Private Dirty/Clean;
Shared Dirty/Clean;
Swap;
SwapPss;
各种 VMA 分类;
memtrack graphics 数据。
5.2 阶段 2:调用目标进程补充运行时数据
如果不是 --local,AMS 随后调用:thread.dumpMemInfo(...), 这里的 thread 是目标应用的 IApplicationThread Binder 接口。AMS 使用 TransferPipe:
TransferPipe tp = new TransferPipe(); thread.dumpMemInfo(tp.getWriteFd(), mi, ...); tp.go(fd, 5000);
普通 dump 超时约 5 秒;--unreachable 路径超时约 30 秒。
注意 Debug.MemoryInfo mi 已经由 system_server 填好,然后通过 Binder parcel 传给目标应用。目标应用不再重新读取 smaps,主要负责补充其内部运行时数据并格式化输出。
6. 目标应用中的 ActivityThread.dumpMemInfo()
实现位于:android\frameworks\base\core\java\android\app\ActivityThread.java(约 1357 行)
目标进程执行:ApplicationThread.dumpMemInfo(...), 然后进入私有 dumpMemInfo()。
6.1 Native Heap 统计
long nativeMax = Debug.getNativeHeapSize() / 1024; long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024; long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
这是 malloc allocator 视角的数据:
Heap Size;
Heap Alloc;
Heap Free。
它们不是 PSS/RSS,而是 allocator 管理的逻辑 heap 数据。
6.2 主动执行一次 GC
源码明确调用:
Runtime runtime = Runtime.getRuntime();
runtime.gc();
随后才统计:
long dalvikMax = runtime.totalMemory() / 1024; long dalvikFree = runtime.freeMemory() / 1024; long dalvikAllocated = dalvikMax - dalvikFree;
所以 dumpsys meminfo <pid> 对应用并非完全无侵入:
(1) 可能触发 ART GC;
(2) 会改变 heap free/alloc;
(3) 可能回收 unreachable Java 对象;
(4) 可能产生短暂暂停;
(5) dump 前后的进程内存状态可能不同。
更微妙的是,执行顺序为:
system_server 先读取 smaps
↓
目标进程再执行 Runtime.gc()
↓
再读取 Dalvik Heap Alloc/Free 和对象数量
因此同一份输出中:
(1) PSS/RSS 是 GC 前后附近的内核快照;
(2) Dalvik Heap Alloc/Free、对象数量是执行 GC 后的结果。
两者并不是严格同一时刻的数据。
如果要尽量避免对目标进程执行 GC,可以使用:adb shell dumpsys meminfo --local <pid>, 但这样不会得到完整的 Heap Alloc、对象数、SQLite 等应用内部统计。
6.3 对象统计
目标进程还会统计:
(1) View 数量;
(2) ViewRootImpl 数量;
(3) ContextImpl 数量;
(4) Activity 数量;
(5) WebView 数量;
(6) OpenSSL Socket 数量;
(7) Asset/AssetManager 数量;
(8) Binder local/proxy/death object;
(9) Parcel 数量及内存;
(10) SQLite page cache 和数据库信息。
这些都不是 /proc/<pid>/smaps 能提供的。
7. Debug.getMemoryInfo() JNI 实现
//Java 声明:android\frameworks\base\core\java\android\os\Debug.java public static native void getMemoryInfo(MemoryInfo memoryInfo); public static native boolean getMemoryInfo(int pid, MemoryInfo memoryInfo); //JNI 注册位置:android\frameworks\base\core\jni\android_os_Debug.cpp { "getMemoryInfo", "(Landroid/os/Debug$MemoryInfo;)V", android_os_Debug_getDirtyPages }, { "getMemoryInfo", "(ILandroid/os/Debug$MemoryInfo;)Z", android_os_Debug_getDirtyPagesPid },
带 PID 的调用进入:android_os_Debug_getDirtyPagesPid()
8. 详细模式为什么必须读取 smaps,不能只读 smaps_rollup
详细实现中的 load_maps() 位于:android\frameworks\base\core\jni\android_os_Debug.cpp
//明确打开: std::string smaps_path = StringPrintf("/proc/%d/smaps", pid); //然后逐个 VMA 调用: meminfo::ForEachVmaFromFile(smaps_path, vma_scan);
详细模式必须使用 smaps,因为要根据每个 VMA 的名字进行分类:
[heap] [anon:libc_malloc] [anon:scudo:*] [stack:*] [anon:dalvik-*] *.so *.jar *.apk *.ttf *.dex / *.odex *.vdex *.oat *.art /dev/kgsl-3d0 /dev/ashmem/* /memfd:jit-cache ...
smaps_rollup 只有进程总量,没有逐 VMA 名称,无法区分 Native Heap、Dalvik Heap、Code、Stack、Ashmem 等类别。
快速统计路径 Debug.getPss() 才使用:/proc/<pid>/smaps_rollup
如果内核不支持再回退到 smaps。实现位于:
//android\system\memory\libmeminfo\procmeminfo.cpp ProcMemInfo::SmapsOrRollupPss(uint64_t* pss) ProcMemInfo::SmapsOrRollup(MemUsage* stats) std::string path = ::android::base::StringPrintf("/proc/%d/%s", pid_, IsSmapsRollupSupported() ? "smaps_rollup" : "smaps");
因此:
-------------------------------------------------------------- 使用场景 数据源 -------------------------------------------------------------- 单 PID 详细 dumpsys meminfo /proc/<pid>/smaps 多进程快速汇总 优先 /proc/<pid>/smaps_rollup Debug.getPss() 优先 smaps_rollup 需要 VMA 分类 必须 smaps --------------------------------------------------------------
9. smaps 字段如何转换成 MemoryInfo
libmeminfo 的解析位于:android\system\memory\libmeminfo\procmeminfo.cpp
主要解析:
Size:
Rss:
Pss:
Private_Clean:
Private_Dirty:
Shared_Clean:
Shared_Dirty:
Swap:
SwapPss:
对应关系如下:
------------------------------------------------------ smaps 字段 MemoryInfo 含义 ------------------------------------------------------ Size 虚拟地址空间大小 Rss 当前驻留物理页总量 Pss 共享页按映射者比例分摊后的驻留量 Private_Clean 进程私有、干净、可回收的驻留页 Private_Dirty 进程私有、脏的驻留页 Shared_Clean 共享干净驻留页 Shared_Dirty 共享脏驻留页 Swap 换出页逻辑原始大小 SwapPss 共享换出页按比例分摊后的逻辑大小 ------------------------------------------------------
USS 的计算是:uss = private_clean + private_dirty; 也就是当前驻留的私有页面,不包含已换出的私有页。
10. VMA 如何分到 Native/Dalvik/Other
load_maps() 对每个 VMA 分类。
(1) Native Heap
以下映射进入 Native Heap:
[heap] [anon:libc_malloc] [anon:scudo:*] [anon:GWP-ASan*]
(2) Dalvik Heap
例如:
[anon:dalvik-alloc space] [anon:dalvik-main space] [anon:dalvik-large object space] [anon:dalvik-non moving space] [anon:dalvik-zygote space]
(3) Dalvik Other
例如:
dalvik-LinearAlloc dalvik-indirect ref dalvik-jit-code-cache dalvik-CompilerMetadata
(4) Code 和文件映射
按文件扩展名分类:
.so .jar .apk .ttf .dex/.odex .vdex .oat .art
(5) Device/Ashmem/Graphics
例如:
/dev/kgsl-3d0 /dev/ashmem/CursorWindow /dev/ashmem/* /memfd:jit-cache
(6) 未匹配的映射进入:
Unknown
Other mmap
Unknown dev
因此 Unknown 并不一定是泄漏,它只是没有命中 Android 分类规则的剩余映射。
11. SwappablePss 不是 SwapPss
源码中还计算一个容易混淆的字段:swappablePss, 其算法大致是:
sharing_proportion = (pss - uss) / (shared_clean + shared_dirty);
swappable_pss = sharing_proportion * shared_clean + private_clean;
它表示:当前仍驻留、但理论上可以通过丢弃文件页重新加载的 PSS。常见来源:
.so;
.apk;
.jar;
.dex;
.oat;
.art;
字体等 clean file mapping。
它和 ZRAM 无关:
--------------------------------------------------------------------- 字段 含义 --------------------------------------------------------------------- SwappablePss/Pss Clean 当前仍驻留但可丢弃重读的文件页 SwapPss 已经换出到 swap/ZRAM 的逻辑页 ---------------------------------------------------------------------
12. Graphics/memtrack 为什么要额外统计
有些 GPU 内存不会完整出现在 /proc/<pid>/smaps,因此 JNI 还调用 memtrack:
read_memtrack_memory(pid, &graphics_mem);
得到:
graphics;
GL;
other memtrack。
随后人工加入:
stats[HEAP_GRAPHICS].pss = graphics_mem.graphics; stats[HEAP_GL].pss = graphics_mem.gl; stats[HEAP_OTHER_MEMTRACK].pss = graphics_mem.other;
同时设置到:
PSS;
Private Dirty;
RSS。
因此可能出现:dumpsys meminfo TOTAL PSS > /proc/<pid>/smaps 中所有 Pss 的总和
差值通常需要检查:
Graphics
GL mtrack
Other mtrack
但 memtrack 依赖 GPU 驱动/HAL 的实现,源码注释也明确提示 graphics 数值可能被驱动错误上报。
13. A12/A14 中 TOTAL PSS 的关键口径
这是需要特别注意的地方。
在两套源码中,Debug.MemoryInfo.getTotalPss() 都定义为:
A12: android\frameworks\base\core\java\android\os\Debug.java A14: android\frameworks\base\core\java\android\os\Debug.java public int getTotalPss() { return dalvikPss + nativePss + otherPss + getTotalSwappedOutPss(); }
也就是:TOTAL PSS = 驻留 Dalvik PSS + 驻留 Native PSS + 驻留 Other PSS + SwapPss。这意味着在你当前 Android 12/14 产品中:dumpsys meminfo 的分类行 PSS 是驻留 PSS,但最终 TOTAL PSS 已经把 SwapPss 加进去了。
例如:
Resident PSS = 300MB
SwapPss = 100MB
最终可能显示:
TOTAL PSS: 400MB
TOTAL SWAP PSS: 100MB
此时不能再计算:TOTAL PSS + TOTAL SWAP PSS,否则会把 SwapPss 重复计算一次。这也对统计是否包含压缩进ZRAM的页和pageout的页做一个源码层面的精确补充:
(1) 单独看 Native/Dalvik/Code 等分类行的 PSS:不包含换出页;
(2) 单独看 RSS:不包含换出页;
(3) 看 SwapPss:是换出页的逻辑比例量;
(4) 看最终 TOTAL PSS:在这两套 A12/A14 源码中,已经包含 SwapPss。
快速路径 Debug.getPss() 也做了相同处理:
pss += stats.pss; swapPss = stats.swap_pss; pss += swapPss;
源码甚至明确注释:// Also in swap, those pages would be accounted as Pss without SWAP
14. 输出表中的 Heap Size/Alloc/Free 与 PSS 没有直接等式关系
典型表格:
# dumpsys meminfo 3222 Pss Private Private SwapPss Rss Heap Heap Heap Total Dirty Clean Dirty Total Size Alloc Free Native Heap Dalvik Heap ... TOTAL
其中左半部分来自内核和 memtrack:
Pss
Private Dirty
Private Clean
SwapPss
Rss
右半部分来自目标进程内部:
Heap Size
Heap Alloc
Heap Free
所以不能假设:Native Heap Alloc == Native Heap PSS, 可能出现:
Native Heap Alloc 500MB
Native Heap PSS 100MB
Native SwapPss 300MB
原因包括:分配但尚未 fault 的虚拟页;页面进入 ZRAM;allocator arena 已保留但部分页可回收;内存碎片;madvise;共享/COW;采集时间不一致。
15. App Summary 是重新归类,不是表格简单相加
打印格式如:
# dumpsys meminfo 3222 App Summary Pss(KB) Rss(KB) ------ ------ Java Heap: 57356 97188 Native Heap: 543024 551016 Code: 545428 734936 Stack: 10060 10072 Graphics: 620190 620190 Private Other: 718068 System: 19149 Unknown: 728924 TOTAL PSS: 2513275 TOTAL RSS: 2742326 TOTAL SWAP (KB): 0
App Summary 的核心计算位于:android\frameworks\base\core\java\android\os\Debug.java
大致口径如下。
(1) Java Heap
dalvikPrivateDirty + private ART image
(2) Native Heap
nativePrivateDirty
(3) Code
包括私有部分:
.so
.jar
.apk
.ttf
.dex
.oat
JIT code cache
(4) Stack
Stack private dirty
(5) Graphics
GL device private + Graphics memtrack + GL memtrack
(6) Private Other
全部 Private Clean/Dirty - Java Heap - Native Heap - Code - Stack - Graphics
(7) System
getTotalPss() - getTotalPrivateClean() - getTotalPrivateDirty()
因为这里的 getTotalPss() 已包含 SwapPss,所以 swap 部分可能落在 Summary 的残差/System 口径中。不要把 App Summary 各项理解成严格的“物理 RAM 分类”。
16. Native 进程的处理不同
如果 PID 没有对应 Android ProcessRecord,AMS 会尝试在 ProcessCpuTracker 中查找 native process。
路径位于:android\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
然后直接在 system_server 中:
Debug.getMemoryInfo(pid, mi);
ActivityThread.dumpMemInfoTable(...);
不会调用目标进程的 IApplicationThread,因为 native daemon 没有该 Binder 接口。所以对 native 进程:
(1) PSS/RSS/SwapPss/VMA 分类仍可获得;
(2) memtrack 可能可获得;
(3) Native Heap Size/Alloc/Free 通常显示 0 或缺失;
(4) 没有 Java Heap;
(5) 没有 View/Activity/SQLite/Binder object 等运行时信息。
17. 性能与准确性限制
17.1 详细模式比较重
读取 /proc/<pid>/smaps 需要:遍历所有 VMA;扫描页表;计算每页 mapcount/PSS;解析每个 VMA 的统计。进程 VMA 很多时,执行时间会明显增加。smaps_rollup 更快,但无法做 Native/Dalvik/Code 等分类。
17.2 不是原子快照
采集过程中目标进程仍可能:malloc/free;mmap/munmap;fault/page-out;创建/退出线程;修改共享页。因此不同统计项之间可能有小幅不一致。
17.3 dump 本身会改变目标状态
普通应用详细 dump 会:发送 Binder;临时解冻进程;执行 GC;遍历对象;查询 SQLite;访问 allocator 状态。如果用于性能或低内存问题分析,不建议高频执行详细 dumpsys meminfo。
17.4 ZRAM 压缩后实际大小不可按 PID获得
SwapPss 是换出页的逻辑原始大小,不是压缩后大小。实际 ZRAM 全局物理成本仍需查看:cat /sys/block/zram0/mm_stat, 重点字段:
orig_data_size
compr_data_size
mem_used_total
其中 mem_used_total 最接近 ZRAM 实际物理成本,但不能精确归属到单个 PID。
18. 推荐验证方式
对同一个 PID 同时抓取:
PID=<pid> dumpsys meminfo $PID dumpsys meminfo --local $PID cat /proc/$PID/smaps_rollup grep -E '^(Rss|Pss|Private|Shared|Swap|SwapPss):' /proc/$PID/smaps_rollup cat /sys/block/zram0/mm_stat
预期关系大致是:
dumpsys 分类 PSS 合计 ≈ smaps resident PSS + memtrack
dumpsys TOTAL RSS ≈ smaps RSS + memtrack RSS
dumpsys TOTAL SWAP PSS ≈ smaps SwapPss
dumpsys TOTAL PSS ≈ smaps PSS + smaps SwapPss + memtrack
最后可以把实现原理概括为:dumpsys meminfo <pid> 由 AMS 的独立 meminfo Binder 服务驱动:system_server 逐 VMA 读取目标进程的 smaps,按映射名称分类并叠加 memtrack;对 Android 应用再通过 IApplicationThread 调用目标进程,获取 GC 后的 ART/malloc heap、对象、Binder、SQLite 等运行时信息,最后由 ActivityThread.dumpMemInfoTable()统一格式化。当前 A12/A14 源码的最终 TOTAL PSS 已包含 SwapPss,而 TOTAL RSS 只表示当前驻留页。
二、trace实测验证
A14_user_2026-09-15_14-32-03.trace //dumpsys meminfo, pid=30345
A14_user_2026-09-15_14-52-52.trace //dumpsys meminfo 3222, pid=8139
A14_user_2026-09-15_14-53-46.trace //dumpsys meminfo --local 3222, pid=8508
1. 逻辑和负载进程分布
三、dumpsys meminfo 与 dumpsys meminfo <pid> 区别
1. 二者对比
---------------------------------------------------------------------------------------------------- 对比项 dumpsys meminfo <pid> dumpsys meminfo ---------------------------------------------------------------------------------------------------- 统计范围 指定一个进程 全部应用进程和 native 进程 dumpDetails 单应用 PID 自动为 true 默认 false 读取 smaps 是,读取一个进程 是,默认读取所有进程 读取 memtrack 是 是,对多个进程 Binder 回调目标应用 是(实测A14是,异步binder发起的) 默认否 目标应用执行 GC 是 默认否 Native/Dalvik Heap Alloc 有 默认不逐进程输出 Objects/View/Activity 有 默认无 SQLite/DB 信息 有 默认无 按进程排序 主要看单进程 有 按 OOM adj 汇总 意义有限 有,主要用途之一 按内存类别汇总 单进程分类 全系统分类 Total/Free/Used/Lost RAM 可能经过公共输出路径,但不是重点 核心输出 ZRAM/KSM/DMA-BUF/GPU 公共 footer 可能显示 核心系统级数据 对目标进程侵入性 较高,会 GC 不逐进程 GC,但全局扫描较重 典型用途 定位某应用的 heap/映射/泄漏 判断整机 RAM 分布和最大占用者 ----------------------------------------------------------------------------------------------------
2. native PID 的特殊情况
dumpsys meminfo $(pidof surfaceflinger)
如果 PID 没有对应 Android ProcessRecord,AMS 会进入 native process 分支:
ProcessCpuTracker 查找 PID --> system_server 调用 Debug.getMemoryInfo(pid) --> 本地 dumpMemInfoTable。
因为 native daemon 没有 IApplicationThread:不会 Binder 回调目标进程;不会触发目标进程 GC;能看到 PSS/RSS/SwapPss/VMA 分类;Native Heap Size/Alloc/Free 通常为 0 或不可用;没有 Activity/View/SQLite 等信息。
所以“带 PID 一定会触发 GC”只对 Android Java 应用进程成立,不适用于普通 native daemon。
3. 参数组合会改变行为
3.1 单 PID 加 --local
dumpsys meminfo --local <pid>
仍然由 system_server 读取:/proc/<pid>/smaps,但不调用:IApplicationThread.dumpMemInfo(),优点:不触发目标进程 GC####(实测的确没有向目标进程发异步binder出发GC);对被测应用干扰较小。缺点:
Heap Size/Alloc/Free 不完整;没有对象、SQLite、Asset 等运行时信息。适合做低干扰的单进程 PSS/RSS/SwapPss 观察。
3.2 不带 PID加 -a
dumpsys meminfo -a
-a 会显式设置:
dumpDetails = true; dumpFullDetails = true; dumpDalvik = true;
这可能对每个 Android 应用调用 dumpMemInfo(),从而逐个触发 GC。这是非常重的命令,不建议在:性能测试;卡顿分析;内存压力测试;启动耗时测试;期间高频执行。
实测,相当于对每一个 pid 都执行一次 dumpsys meminfo <pid>
3.3 不带 PID加 --oom
dumpsys meminfo --oom
oomOnly=true 后,不需要完整分类时可以进入:Debug.getPss(pid, ...), 快速路径优先读取:/proc/<pid>/smaps_rollup, 它通常比遍历每个进程的完整 smaps 更轻,适合观察各 oom_adj 层级的总体内存。
posted on 2026-09-15 15:37 Hello-World3 阅读(12) 评论(0) 收藏 举报
浙公网安备 33010602011771号