社区互动

adb shell 查询Android应用cpu内存占用及优化

在Android系统性能分析时,经常会拿到系统历史cpu和内存占用日志,

来分析某段时间哪些应用cpu和内存占用是否特别高以及变化来确定应用内存或cpu是否需要优化。

一、cpu占用查询及优化

1.获取系统中所有应用的cpu占用

adb shell top 获取系统中所有应用cpu占用并按照cpu占用率从大到小排序。

参数-m 可以指定 最多显示多少个进程

2.获取某个应用cpu内存占用率

先通过命令获取包名对应的pid,命令:adb shell pidof 应用包名

lilei@lilei-HP-Z4-G4-Workstation:~$ adb shell pidof 应用包名

3642

2.1 然后根据进程id(3642)获取该应用cpu占用情况,

命令:adb shell top -b -n 1 -p 3642,

查找包含pid 3642第9列就是cpu占用率0.0%内存占用率1.6

lilei@lilei-HP-Z4-G4-Workstation:~$ adb shell top -b -n 1 -p 3642

Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie

Mem: 11400952K total, 7869960K used, 3530992K free, 40607744 buffers

Swap: 3145724K total, 0 used, 3145724K free, 2803496K cached

800%cpu 221%user 0%nice 125%sys 429%idle 0%iow 18%irq 7%sirq 0%host

PID USER PR NI VIRT RES SHR S[%CPU] %MEM TIME+ ARGS

3642 system -2 0 16G 183M 129M S 0.0 1.6 0:14.44 应用包名

2.2 然后根据进程id(3642)获取该应用各个线程占用cpu情况,

命令:adb shell top -H -d 1 -p 3642 -O cpu

TID列:线程ID(主线程TID通常等于PID)。

THREAD列:线程命名,建议在代码中为重要线程设置可识别名称。

[CPU]列:显示线程运行的物理核心位置(静态位置信息)。

%CPU列:显示线程的CPU使用率百分比(动态资源消耗)。

Threads: 32 total, 0 running, 32 sleeping, 0 stopped, 0 zombie

Mem: 11400952K total, 8106876K used, 3294076K free, 61607936 buffers

Swap: 3145724K total, 0 used, 3145724K free, 2929148K cached

800%cpu 223%user 0%nice 131%sys 421%idle 0%iow 17%irq 8%sirq 0%host

TID USER [CPU]%CPU %MEM TIME+ THREAD PROCESS

30998 system 4 0.0 1.6 0:00.00 AdrenoOsLib 应用包名

30962 system 5 0.0 1.6 0:00.15 RenderThread 应用包名

9141 system 2 0.0 1.6 0:00.00 Binder:3642_5 应用包名

4172 system 7 0.0 1.6 0:00.00 queued-work-loo 应用包名

3987 system 4 0.0 1.6 0:02.07 subscriber 应用包名

3985 system 2 0.0 1.6 0:00.00 ion.xxxxxxxxxxxx 应用包名

3984 system 3 0.0 1.6 0:00.00 ion.xxxxxxxxxxxx 应用包名

3982 system 2 0.0 1.6 0:02.44 ion.xxxxxxxxxxxx 应用包名

3981 system 2 0.0 1.6 0:00.00 ion.xxxxxxxxxxxx 应用包名

3979 system 2 0.0 1.6 0:01.67 VATimer 应用包名

3977 system 3 0.0 1.6 0:00.00 Thread-3 应用包名

3976 system 3 0.0 1.6 0:00.00 Thread-2 应用包名

3963 system 3 0.0 1.6 0:00.00 DmsSceneWorkerT 应用包名

3962 system 3 0.0 1.6 0:00.00 Speech_HT 应用包名

3961 system 7 0.0 1.6 0:00.18 MSG_BASE_MODULE 应用包名

3960 system 3 0.0 1.6 0:00.00 StatisticsWorke 应用包名

3959 system 6 0.0 1.6 0:00.00 Rpc-Handler 应用包名

3958 system 3 0.0 1.6 0:00.00 HwBinder:3642_1 应用包名

3935 system 2 0.0 1.6 0:00.09 Binder:3642_4 应用包名

920 system 5 0.0 1.6 0:00.20 Profile Saver 应用包名

3.获取一段时间应用各个线程的cpu占用

profile 分析cpu trace文件 分析一段时间应用各个线程的cpu占用情况

在Androidstudio 的profile界面 点击+号-load from file

例如:cpu-simpleperf-20250418T154823.trace 文件

如截图所示:

1.选择 All threads tab

2.选择 Top down tab

3.选择 Thread Time 下拉框

列表界面会显示该trace 文件统计时间段内,每个线程的cpu耗时间及百分比,基于CPU占用大的线程做cpu优化。

4.CPU 优化方法

1.初始化任务优先级分配,削峰填谷。

2.非必要内容,延迟初始化。

3.资源拷贝优化,减少读取IO时间。

3.线程池复用,减少CPU调度开销。

4.线程命名,方便定位问题。

二、内存占用查询及优化

1.获取系统中所有应用的内存占用

命令:adb shell dumpsys meminfo

可以查询系统所有应用的内存占用及占用排序。

2.获取某个应用内存占用 大小

dumpsys meminfo 应用包名,查询应用内存占用,如下dumpsys信息中第一个包含TOTAL关键字行第二列就是应用的总内存为84415(KB)

TOTAL 84415 32336 43068 0 84415 37040 23405 9641

lilei@lilei-HP-Z4-G4-Workstation:~$ adb shell dumpsys meminfo 应用包名

Applications Memory Usage (in Kilobytes):

Uptime: 5566435 Realtime: 5566435

** MEMINFO in pid 3642 [应用包名] **

Pss Private Private Swap Rss Heap Heap Heap

Total Dirty Clean Dirty Total Size Alloc Free

------ ------ ------ ------ ------ ------ ------ ------

Native Heap 14231 14200 0 0 17256 25848 17809 4045

Dalvik Heap 4716 4652 0 0 9108 11192 5596 5596

Dalvik Other 3302 2412 0 0 4808

Stack 840 840 0 0 848

Cursor 2 0 0 0 4

Ashmem 2 0 0 0 8

Other dev 160 0 160 0 444

.so mmap 7128 624 1644 0 53852

.jar mmap 1103 0 20 0 30596

.apk mmap 27710 148 26900 0 30404

.ttf mmap 45 0 0 0 288

.dex mmap 0 0 0 0 132

.oat mmap 26 0 0 0 2440

.art mmap 7751 7580 0 0 20256

Other mmap 16815 1312 14344 0 20544

Unknown 584 568 0 0 1252

TOTAL 84415 32336 43068 0 84415 37040 23405 9641

App Summary

Pss(KB) Rss(KB)

------ ------

Java Heap: 12232 29364

Native Heap: 14200 17256

Code: 29380 119628

Stack: 840 848

Graphics: 0 0

Private Other: 18752

System: 9011

Unknown: 25144

TOTAL PSS: 84415 TOTAL RSS: 192240 TOTAL SWAP (KB): 0

Objects

Views: 337 ViewRootImpl: 1

AppContexts: 6 Activities: 1

Assets: 6 AssetManagers: 0

Local Binders: 53 Proxy Binders: 51

Parcel memory: 7 Parcel count: 28

Death Recipients: 23 OpenSSL Sockets: 0

WebViews: 0

SQL

MEMORY_USED: 0

PAGECACHE_OVERFLOW: 0 MALLOC_SIZE: 0

3.获取一段时间后应用创建对象内存占用

profile 分析memory hprof 文件 分析一段时间后应用创建对象内存占用情况

在Androidstudio 的profile界面 点击+号-load from file

例如:memory-20250418T161446.hprof 文件

如截图所示:

3.1.选择 View app heap 下拉框

查看当前应用的内存堆栈

3.2.选择 Arrange by package 下拉框

按照包名称分组

3.3.选择 Show project classes 下拉框

显示当前应用的类

3.4.选中要查看的类

3.4.1在Package Name界面:

#1 Allocations 列对应 创建类对象的个数

#2 Native Size列为(本地内存)

定义:通过 JNI(Java Native Interface)或 Native 代码(如 C/C++)直接分配的内存

典型场景:OpenGL 纹理、位图像素数据(如 Bitmap 的像素存储在 Native 层)

第三方 Native 库(如音视频编解码库)分配的内存

#3 Shallow Size列为(浅层内存)

定义:对象 自身实例占用的内存(不含其引用的其他对象)。

计算方式:

对象头(类型指针、锁状态等) + 成员变量(基础类型直接存储,引用类型仅存储指针)

示例:

一个 ArrayList 实例的 Shallow Size 包含数组指针、容量等元信息,但不包含实际存储的元素对象内存

#4 Retained Size列为(保留内存)

定义:对象被回收后,连带释放的所有内存(包括其直接和间接引用的对象)

重要性:用于判断内存泄漏的关键指标。

示例:

一个泄漏的 Activity 若持有大量 View 和资源,其 Retained Size 会非常高(包括整个视图树及相关资源)

分析步骤:

在 Profiler 中筛选 Retained Size 高的对象。通过 Show Path to GC Roots检查强引用链,定位泄漏源

在Package Name界面:

3.4.2在Instance 界面:

选中类创建的每个对象实例的内存占用情况

3.4.3在Instance Details 界面:

#1 Filelds tab

显示选中类中创建的对象内存占用

#2 References tab

显示选中类被哪些类 创建引用

4.内存 优化方法

4.1、内存抖动

现象:应用内存波动图形呈 锯齿状。

原因:程序中频繁创建对象会导致内存频繁分配和回收。

优化方向:减少在循环或频繁调用的方法中创建对象,可以使用缓存机制或对象池来复用对象。

如:使用StringBuilder或String.format等方法进行字符串拼接,避免使用加号拼接,以减少临时对象的生成等。

4.2、内存泄漏

现象:应用内存不断增长

原因:对象被持有导致无法释放或不能按照对象正常的生命周期进行释放

优化方向:

1.避免单例模式持有外部类的引用。

2.避免非静态内部类或匿名类默认持有外部类的引用。

3避免静态成员变量持有外部类的引用造成的内存泄漏。

4.广播不需要监听时需要及时注销。

5.数据库游标Cursor不用时需要及时释放。

6.WebView不需要展示时需要及时释放webview的资源。

4.3、内存溢出

现象:E/AndroidRuntime(13316): java.lang.OutOfMemoryError

原因:内存泄漏累积到一定程度导致OOM,或者一次性申请很多内存

优化方向:

1.避免内存泄露。

2..避免一次创建大的数组或者是载入大的文件如图片。