☰
Android dumpsys 命令实战:从内存泄漏到卡顿排查的完整指南
2026/10/13 10:47:19 网站建设 项目流程

1. 为什么我劝你把 dumpsys 用起来

做 Android 开发或者测试这行,很多人一提到调试,第一反应就是打开 IDE 的 Logcat 面板,或者连上调试器打断点。这些方法当然没问题,但有个前提——你得有源码、有工程、能编译。可现实里经常遇到的情况是:手上只有一台设备和一个 APK,或者线上出了个偶发问题,日志里啥也看不出来,这时候你怎么办?

我做了十来年移动端,踩过太多这种坑。后来发现,真正能在关键时刻救命的,往往是系统自带的那套命令行工具,而dumpsys就是其中最被低估的一个。它不需要你改一行代码,不需要重新打包,只要设备能连上,一条命令就能把系统内部的状态全给你倒出来。dumpsys 是 Android 系统内置的一个诊断工具,全称是 dump system,它能输出各个系统服务的运行状态、内部数据结构、配置参数等海量信息,从 Activity 栈、内存占用、电池统计到网络连接、传感器状态,几乎无所不包。

这篇文章适合谁看?如果你是刚入行的 Android 开发者,想搞明白系统到底是怎么运转的;如果你是测试工程师,经常需要定位一些"说不清道不明"的问题;如果你是性能优化方向的从业者,想找一套不依赖 IDE 的排查手段——那这篇内容你应该会感兴趣。我会从整体思路讲到具体命令,再到实际排查案例,尽量把每个参数背后的逻辑都讲清楚,让你看完就能上手抄作业。

需要提前说明的是,dumpsys输出的信息量非常大,直接裸跑一条adb shell dumpsys能刷屏几万行,新手很容易被淹没。所以关键不在于"会不会敲命令",而在于"知不知道该看哪个服务、怎么过滤、怎么解读"。这也是我下面要重点拆解的东西。

2. 整体设计思路与命令结构拆解

2.1 dumpsys 到底是个什么东西

从系统架构的角度看,Android 的很多核心功能都是以"系统服务"的形式存在的,比如管理窗口的 WindowManagerService、管理 Activity 生命周期的 ActivityManagerService、负责电源的 PowerManagerService 等等。这些服务都运行在 system_server 进程里,各自维护着一大堆内部状态。

dumpsys本质上就是一个客户端程序,它通过 Binder 机制向这些系统服务发起调用,让每个服务把自己的状态"吐"出来。每个系统服务都实现了dump()方法,具体输出什么内容、支持哪些参数,完全由服务自己决定。这就解释了为什么不同服务的输出格式千差万别——因为它们本来就是不同的人、在不同的时期写的。

理解这一点很重要,因为它决定了你使用dumpsys的基本姿势:先确定你要查的是哪个服务,再去看这个服务支持哪些参数。而不是漫无目的地乱敲。

2.2 命令的基本语法结构

dumpsys的命令格式其实很规整,标准写法是这样的:

adb shell dumpsys [服务名] [参数...]

拆开来看,adb shell是进入设备执行命令的入口,dumpsys是工具本身,后面的服务名和参数都是可选的。如果不带任何参数,它会输出所有服务的状态,那个量级基本没法看。所以实战中我们几乎总是要指定服务名。

想看看设备上到底有哪些服务可以查,可以跑这条:

adb shell dumpsys -l

它会列出当前系统注册的所有服务名,通常有上百个。常见的比如activity、window、battery、meminfo、package、wifi、connectivity、sensorservice等等。这个列表在不同 Android 版本、不同厂商 ROM 上会有差异,所以换设备时最好重新看一眼。

还有一个很实用的参数是-t,用来控制超时时间:

adb shell dumpsys -t 10 activity

有些服务在 dump 的时候会做比较重的操作,如果卡住了,加上超时能避免命令一直挂着。默认超时是 5 秒,遇到输出特别慢的服务可以适当调大。

2.3 为什么选择命令行而不是图形工具

这里可能有人会问:现在不是有很多图形化的调试工具吗,为什么还要用命令行?

我的经验是,图形工具适合"已知问题、按图索骥",而命令行适合"未知问题、全面扫描"。举个实际场景:某个页面在特定机型上偶发卡顿,日志里没有任何异常,图形工具也看不出所以然。这时候你用dumpsys gfxinfo把渲染数据拉出来,往往能看到某一帧的绘制时间异常,进而定位到是哪个环节拖了后腿。

另外,命令行工具还有个天然优势——可脚本化。你可以把dumpsys的输出重定向到文件,用 grep、awk 这些工具做二次处理,甚至写个脚本定时采集。这在做性能监控、批量测试的时候特别有用,图形工具很难做到这一点。

提示:dumpsys的输出格式在不同 Android 版本之间可能变化,写解析脚本时不要把字段位置写死,尽量用关键字匹配。

3. 核心服务与常用命令详解

3.1 activity 服务:看清页面栈的真面目

activity是我用得最多的一个服务,没有之一。它能告诉你当前设备上所有 Activity 的状态、任务栈的分布、进程的优先级等等。

最常用的命令是:

adb shell dumpsys activity activities

这个命令会输出所有 Activity 栈的信息。输出里你会看到类似TaskRecord、ActivityRecord、Hist #0这样的结构。简单解释一下:TaskRecord代表一个任务栈,ActivityRecord代表栈里的一个 Activity 实例,Hist后面的数字表示它在栈中的位置,数字越小越靠近栈顶。

如果你只想看当前处于前台的 Activity,可以用:

adb shell dumpsys activity top

或者更直接一点:

adb shell dumpsys activity activities | grep -E "mResumedActivity|mFocusedActivity"

不同版本字段名不太一样,新版本用mResumedActivity,老版本可能是mFocusedActivity。这个技巧在自动化测试里特别有用,可以用来断言"当前页面是不是我期望的那个"。

还有一个我经常用的子命令是查看进程信息:

adb shell dumpsys activity processes

它会列出所有进程的 oom_adj 值、进程状态、包含的组件等。oom_adj 这个值很关键,它决定了系统在内存紧张时优先杀谁。数值越小越"重要",前台进程通常是 0,可见进程是 100 左右,后台进程可能到 700 以上。如果你发现自己的应用莫名其妙被杀,可以来这里看看它的 oom_adj 是不是偏高。

3.2 meminfo 服务:内存问题的第一现场

内存泄漏、OOM、频繁 GC,这些问题的排查都离不开meminfo。

adb shell dumpsys meminfo

不带参数时,它会输出所有进程的内存概览,按 PSS 从大到小排序。PSS 是 Proportional Set Size 的缩写,简单理解就是"这个进程实际占了多少物理内存",共享库的内存会按比例分摊。看这个列表,你能一眼发现哪个进程是内存大户。

想深入看某个应用,就带上包名:

adb shell dumpsys meminfo com.example.app

输出会分成好几块,我重点说几个关键指标:

指标含义关注点
Java HeapJava 堆内存持续增长可能是泄漏
Native HeapNative 堆内存图片、音视频相关
Graphics图形内存纹理、Surface 占用
Private Dirty私有脏页真正独占的物理内存
PSS Total总 PSS综合内存占用

我个人的经验是,排查内存问题不要只看单次数据,要做对比。比如打开某个页面前后各 dump 一次,看哪块内存涨得最明显。如果 Java Heap 涨了但 GC 之后降不下来,那基本就是泄漏了,接下来就该上 MAT 或者 LeakCanary 了。

注意:dumpsys meminfo本身会触发一次 GC 相关的统计,对性能有轻微影响,不要在高频循环里调用。

3.3 battery 服务:耗电分析的起点

耗电问题向来是移动端的重灾区,battery服务能给你提供第一手的统计数据。

adb shell dumpsys battery

这个命令输出的是当前电池的即时状态:电量、温度、电压、充电状态、健康度等。看起来简单,但结合场景能看出不少东西。比如温度异常高,可能是某个模块在疯狂跑;充电状态频繁切换,可能是充电 IC 或者线材有问题。

更详细的历史统计要用:

adb shell dumpsys batterystats

这个输出非常庞大,包含唤醒锁、网络使用、传感器、各应用的耗电估算等。实战中我一般会配合--reset先清空数据,跑一段时间后再 dump,这样数据更干净:

adb shell dumpsys batterystats --reset # 使用一段时间后 adb shell dumpsys batterystats > battery.txt

输出里有个Wake lock部分特别值得看,它能告诉你哪些应用持有唤醒锁、持有了多久。唤醒锁是耗电大户,一个不释放的唤醒锁能让设备一直无法进入休眠。

3.4 gfxinfo 服务:卡顿问题的照妖镜

界面卡顿是用户最容易感知的问题,gfxinfo能把每一帧的渲染数据都给你列出来。

adb shell dumpsys gfxinfo com.example.app

输出里最核心的是Draw、Prepare、Process、Execute这几个阶段的耗时。它们分别对应 UI 线程的测量布局绘制、同步准备、渲染线程的处理和执行。如果某一帧的总耗时超过 16.67ms(60Hz 屏幕),就会掉帧。

想拿到更结构化的数据,可以加framestats参数:

adb shell dumpsys gfxinfo com.example.app framestats

它会输出一个 CSV 格式的帧数据表,每一行是一帧,每一列是不同阶段的耗时(单位纳秒)。这个数据可以直接导入表格做分析,或者写脚本算 P90、P99 分位值。

我一般会这样用:先reset清空统计,然后手动滑动页面几十秒,再 dump 出来看。这样得到的数据最能反映真实滑动场景下的表现。

adb shell dumpsys gfxinfo com.example.app reset # 手动操作页面 adb shell dumpsys gfxinfo com.example.app > gfx.txt

3.5 package 服务:应用信息的百宝箱

package服务能查的东西非常多,从已安装应用列表到权限授予情况,从组件信息到签名摘要。

查某个应用的详细信息:

adb shell dumpsys package com.example.app

输出里包含版本号、安装路径、数据目录、声明的权限、四大组件列表、签名信息等。我经常用它来确认几件事:应用是不是被降级安装了、权限有没有被用户手动关掉、某个 Service 是不是真的注册成功了。

查权限相关的:

adb shell dumpsys package permissions

这个能列出所有权限的定义和授予状态。做权限适配的时候,来这里看一眼比翻文档快多了。

3.6 window 服务:窗口层级与焦点

window服务主要用来分析窗口的层级关系、焦点归属、显示区域等。

adb shell dumpsys window windows

输出里会列出所有窗口,包括它们的类型、层级、可见性、焦点状态。排查"点击没反应"这类问题时特别有用——很可能是某个透明窗口盖在上面把点击事件拦截了。

看当前焦点窗口:

adb shell dumpsys window | grep mCurrentFocus

这个在自动化测试里也是高频操作,用来判断弹窗有没有正常弹出。

4. 实操流程与典型排查案例

4.1 环境准备与基础连接

在开始之前,先把环境搭好。你需要一台开启了 USB 调试的设备,以及装好 platform-tools 的电脑。连接命令很简单:

adb devices

能列出设备就说明连接正常。如果显示unauthorized,去设备上确认一下调试授权弹窗;如果显示offline,试试重新插拔或者重启 adb 服务:

adb kill-server adb start-server

我建议在正式排查前,先跑一遍adb shell dumpsys -l确认服务列表,顺便看看设备是什么 Android 版本:

adb shell getprop ro.build.version.release

不同版本的服务名和输出格式有差异,提前确认能少走弯路。

4.2 案例一:定位一个"页面打不开"的问题

之前遇到过一个情况:用户反馈点击某个入口后页面白屏,但日志里没有任何崩溃信息。这种问题用常规手段很难查,我是这么做的。

第一步,确认当前页面栈:

adb shell dumpsys activity activities | grep -E "Hist|mResumedActivity"

结果发现目标 Activity 确实被启动了,而且处于 resumed 状态。说明页面不是没打开,而是打开了但内容没渲染出来。

第二步,看窗口状态:

adb shell dumpsys window windows | grep -A 5 "目标Activity名"

发现窗口是可见的,尺寸也正常。那问题就出在内容渲染上。

第三步,看渲染数据:

adb shell dumpsys gfxinfo 包名

发现帧数据几乎为空,说明根本没有触发绘制。结合代码排查,最后定位到是数据加载的回调没有触发,导致 View 一直是空的。整个过程没改一行代码,全靠dumpsys把问题范围一步步缩小。

4.3 案例二:内存持续增长的排查

另一个典型案例是内存问题。某应用在长时间使用后内存涨到 1G 以上,被系统频繁回收。

先看整体内存分布:

adb shell dumpsys meminfo 包名

发现 Java Heap 占了 600M 多,明显不正常。然后做前后对比:进入某页面之前 dump 一次,退出后再 dump 一次,发现 Java Heap 只涨不降。基本可以确定是泄漏。

接下来用dumpsys meminfo的详细模式看对象分布:

adb shell dumpsys meminfo 包名 -d

-d参数会输出更细的对象统计。虽然不如 MAT 直观,但能快速看出是哪类对象数量异常。当时发现某个自定义 View 的实例数量远超预期,顺着这条线索找到了监听器没注销的问题。

4.4 案例三:耗电异常的快速定位

有段时间测试机待机耗电特别快,一晚上掉 30%。用batterystats一查就清楚了。

先重置数据:

adb shell dumpsys batterystats --reset

放置几小时后 dump:

adb shell dumpsys batterystats > battery.txt

在输出里搜Wake lock,发现某个应用持有一个唤醒锁长达数小时。再看Sensor部分,发现加速度传感器一直在工作。两个线索一结合,问题就明确了——某个后台服务没有正确释放资源。

4.5 输出重定向与二次处理技巧

dumpsys的输出动辄几千上万行,直接在终端看很痛苦。我习惯重定向到文件:

adb shell dumpsys activity activities > activity.txt

然后用 grep 过滤关键字:

grep -n "mResumedActivity" activity.txt

如果要跨多次采集做对比,可以用 diff:

diff before.txt after.txt

在 Windows 上可以用 PowerShell 的Select-String替代 grep。如果要做更复杂的分析,把数据导出成 CSV 再用 Python 处理是最灵活的。比如解析gfxinfo framestats的输出算掉帧率,我写过一个几十行的小脚本,比手动看快得多。

提示:采集数据时尽量保持设备状态一致,比如都充满电、都清空后台,否则数据没有可比性。

5. 常见问题与避坑经验实录

5.1 命令报错与权限问题

新手最常遇到的就是权限报错,比如Permission Denial或者SecurityException。这是因为部分服务的 dump 需要特定权限,普通应用进程调不了。解决办法有两个:一是用adb shell以 shell 用户身份执行(大多数服务 shell 都有权限),二是设备需要 root。实战中前者基本够用。

还有一种情况是命令执行后没有任何输出。这通常是因为服务名写错了,或者该服务在当前设备上不存在。先用dumpsys -l确认服务名,注意大小写敏感。

5.2 输出太多找不到重点

这是最普遍的问题。我的建议是养成"先过滤再细看"的习惯。常用的过滤手段有这么几种:

  • 用grep匹配关键字,比如grep "mResumedActivity"
  • 用-A、-B参数看上下文,比如grep -A 10 "关键字"
  • 用head、tail限制行数,先看个大概
  • 把输出存文件,用编辑器搜索

另外,很多服务支持子命令来缩小范围。比如dumpsys activity后面可以跟activities、processes、services等,比裸跑精确得多。

5.3 不同版本输出格式不一致

这个问题很烦人,尤其是写自动化脚本的时候。Android 每个大版本都可能调整 dump 的格式,字段名、缩进、顺序都可能变。我的应对策略是:永远用关键字匹配,不要依赖固定行号或列位置。比如找前台 Activity,用grep mResumedActivity比用sed -n '5p'靠谱得多。

如果要做跨版本的兼容,建议先采集几个版本的样本,找出稳定的关键字,再写解析逻辑。

5.4 常见问题速查表

问题现象可能原因排查命令
命令无输出服务名错误或不存在dumpsys -l
权限拒绝需要 root 或 shell 权限用adb shell执行
输出卡住服务 dump 耗时过长加-t超时参数
数据不准确统计未重置先执行--reset
格式对不上版本差异用关键字匹配
内存数据波动大采样时机不一致固定场景对比采集

5.5 几个我踩过的坑

第一个坑是在循环里高频调用 dumpsys。有次我写了个脚本每秒 dump 一次 meminfo,结果设备直接卡死。原因是 dump 操作本身会暂停目标服务的部分工作,高频调用等于持续干扰系统运行。后来改成 5 秒一次,问题就没了。

第二个坑是忽略了 dump 本身的性能开销。dumpsys gfxinfo在采集帧数据时会影响渲染性能,所以采集期间的数据不能完全代表真实表现。我的做法是采集时尽量模拟真实操作,但心里清楚有轻微偏差。

第三个坑是把不同时间点的数据直接对比。设备温度、后台应用、电量状态都会影响数据,不做控制变量的对比基本没有意义。现在我采集前都会先清后台、等设备降温、确认电量相近,虽然麻烦但数据可信度高很多。

第四个坑是过度依赖单一指标。比如只看 PSS 判断内存问题,忽略了 Graphics 和 Native Heap。实际上很多内存问题出在 Native 层,光看 Java Heap 会漏掉。多维度交叉验证才是正道。

5.6 提升效率的几个小技巧

把常用命令做成别名或者脚本,能省不少事。比如我在.bashrc里加了几个 alias:

alias dact='adb shell dumpsys activity activities' alias dmem='adb shell dumpsys meminfo' alias dgfx='adb shell dumpsys gfxinfo'

另外,dumpsys的输出可以配合watch命令做实时监控:

watch -n 2 "adb shell dumpsys meminfo 包名 | head -20"

这样每两秒刷新一次内存概览,观察趋势很方便。不过记得别把间隔设太短,前面说过高频调用有副作用。

最后再分享一个我个人的习惯:每次排查完问题,把当时的命令和关键输出片段记到笔记里。时间长了就形成自己的"命令库",下次遇到类似问题直接翻笔记,比重新摸索快得多。dumpsys这个工具的魅力就在于,你用得越多,越能发现它的深度——它不只是一个命令,而是理解 Android 系统运行机制的一扇窗。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询