App性能优化——内存、CPU、耗电、启动时间指标获取分析

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 考虑到既然是优化性能,那首先要获取App的相关性能指标,比如: 内存占用、CPU利用率、App启动时间、App耗电量等情况,获取以上各指标后,才能针对性分析确定是否存在优化的可能。

Android App性能优化 (内存、CPU、耗电量、启动时间指标获取)

最近公司要求对App进行性能优化。考虑到既然是优化性能,那首先要获取App的相关性能指标,比如: 内存占用CPU利用率App启动时间App耗电量等情况,获取以上各指标后,才能针对性分析确定是否存在优化的可能。

  • 查看App启动时间(冷启动、热启动)
  • 查看进程内存占用
  • 查看进程CPU使用率
  • 查看App耗电量

一、App启动时间

本小节记录以下三个adb shell 命令:

  • adb shell am start -W [包名]

启动APP,查询App的启动时间

  • adb shell am start -n [包名]/[包名.Activity]

启动一个Activity(不记录启动时间)

  • adb shell am force-stop [包名]

关闭一个APP进程

1.1、App启动时间

查询App的启动时间,可以用以下命令:

// 启动APP,查询App的启动时间
// adb shell am start -W [包名]
adb shell am start -W com.xiaxl.demo

adb shell 查询App启动时间

查询结果中,对应的时间参数详细解析如下:

  • ThisTime:对应activity启动耗时;
  • TotalTime:应用自身启动耗时 = ThisTime + 应用application等资源启动时间
  • WaitTime:系统启动应用耗时 = TotalTime + 系统资源启动时间

1.2、启动一个Activity(不记录启动时间)

单纯启动一个Activity,不记录启动时间,可以使用以下命令。

// 启动一个Activity(不记录启动时间)
// adb shell am start -n [包名]/[包名.Activity]
adb shell am start -n com.xiaxl.demo/com.volley.demo.DmTestActivity

adb shell 启动一个Activity(不记录启动时间)

示例图中,对应Activity在AndroidManifest.xml中的声明方式如下:

<activity
    android:name="com.volley.demo.DmTestActivity"
    android:exported="true"></activity>

1.3、关闭一个App进程

关闭一个App进程用如下命令。

// 关闭一个APP进程用如下命令。
// adb shell am force-stop [包名]
adb shell am force-stop com.xiaxl.demo

adb shell 关闭一个APP进程

二、进程内存占用

本小节记录以下四个adb shell 命令:

  • adb shell dumpsys meminfo [进程名]

Android系统中,查看某一进程的内存占用情况

  • adb shell ps

Android系统中,显示全部系统进程

  • adb shell ps | grep [keyword]

Android系统中,筛选包含特定关键词的进程

  • adb shell cat /proc/meminfo

Android系统中,查看整个系统的内存详情

2.1、查看进程内存占用

Android系统中,查看某一进程的内存占用情况可以使用以下命令。

// 查看Android系统中,某一进程的内存占用情况
// adb shell dumpsys meminfo [进程名]
adb shell dumpsys meminfo com.xiaxl.demo

adb shell查看进程内存占用

以上截图中 TOTAL 字段,为对应进程占用的系统总内存;其他字段不再做详细介绍。

2.2、显示全部系统进程

Android系统中,若不了解对应进程的进程名称,可用如下命令显示全部系统进程

// Android系统中,显示全部系统进程
adb shell ps

adb shell 显示全部系统进程

2.3、筛选进程

Android系统中,亦可根据特定关键词,筛选包含特定关键词的进程

// Android系统中,筛选包含特定关键词的进程
adb shell ps | grep [keyword]

adb shell 筛选包含特定关键词的进程

2.4、查看系统内存详情

Android系统中,如果需要查看整个系统的内存详情,可以使用以下命令。

// Android系统中,查看整个系统的内存详情
adb shell cat /proc/meminfo 

adb shell 查看系统的内存详情

相关参数的详细解释如下所示:

MemTotal:         688576 kB     总内存
MemFree:          153736 kB     空闲内存
MemAvailable:     339884 kB     可用内存
Buffers:              16 kB     给文件的缓冲大小
Cached:           267672 kB     高速缓冲存储器
SwapCached:           36 kB     被高速缓冲存储用的交换空间的大小
Active:           222900 kB     活跃使用中的高速缓冲存储器页面文件大小
Inactive:         123700 kB     不经常使用中的告诉缓冲存储器文件大小
Active(anon):      31800 kB     活跃的匿名内存(进程中堆上分配的内存,是用malloc分配的内存)
Inactive(anon):    57272 kB     不活跃的匿名内存
Active(file):     191100 kB     活跃的file内存
Inactive(file):    66428 kB    不活跃的file内存     
Unevictable:           0 kB    不能被释放的内存页
Mlocked:               0 kB    mlock()系统调用锁定的内存大小
SwapTotal:       2097148 kB    交换空间总大小
SwapFree:        2096884 kB    空闲交换空间
Dirty:                 0 kB    等待被写回到磁盘的大小
Writeback:             0 kB    正在被写回的大小
AnonPages:         78876 kB       未映射页的大小
Mapped:            28556 kB    设备和文件映射大小
Shmem:             10160 kB    已经被分配的共享内存大小
Slab:             102916 kB    内核数据结构缓存大小
SReclaimable:      49616 kB    可收回slab的大小
SUnreclaim:        53300 kB    不可回收的slab的大小
KernelStack:        4416 kB      kernel消耗的内存
PageTables:         6028 kB      管理内存分页的索引表的大小
NFS_Unstable:          0 kB      不稳定页表的大小
Bounce:                0 kB      在低端内存中分配一个临时buffer作为跳转,把位于高端内存的缓存数据复制到此处消耗的内存
WritebackTmp:          0 kB      USE用于临时写回缓冲区的内存
CommitLimit:     2441436 kB      系统实际可分配内存总量
Committed_AS:     308028 kB      当前已分配的内存总量
VmallocTotal:   34359738367 kB   虚拟内存大小
VmallocUsed:      179588 kB    已经被使用的虚拟内存大小
VmallocChunk:   34359310332 kB   malloc 可分配的最大的逻辑连续的内存大小
HardwareCorrupted:     0 kB      删除掉的内存页的总大小(当系统检测到内存的硬件故障时)
AnonHugePages:      6144 kB      匿名 HugePages 数量
CmaTotal:              0 kB    总的连续可用内存
CmaFree:               0 kB      空闲的连续内存
HugePages_Total:       0      预留HugePages的总个数 
HugePages_Free:        0     池中尚未分配的 HugePages 数量
HugePages_Rsvd:        0        表示池中已经被应用程序分配但尚未使用的 HugePages 数量
HugePages_Surp:        0      这个值得意思是当开始配置了20个大页,现在修改配置为16,那么这个参数就会显示为4,一般不修改配置,这个值都是0
Hugepagesize:       2048 kB     每个大页的大小
DirectMap4k:      108416 kB   映射TLB为4kB的内存数量
DirectMap2M:      940032 kB   映射TLB为2M的内存数量
DirectMap1G:           0 kB     映射TLB为1G的内存数量

三、进程CPU占用

本小节记录以下两个adb shell 命令:

  • adb shell dumpsys cpuinfo | grep [进程名]

Android系统中,查看某一进程的CPU占用情况情况

  • adb shell cat /proc/cpuinfo

Android系统中,查看CPU各核心详情

3.1、进程CPU占用

Android系统中,筛选查看某一进程的CPU占用情况可以使用以下命令。

// 查看Android系统中,筛选某一进程的CPU占用情况
adb shell dumpsys cpuinfo | grep [进程名]

// 查看Android系统,CPU占用情况(各进程CPU占用,总的CPU占用)
adb shell dumpsys cpuinfo

adb shell dumpsys cpuinfo | grep [进程名] 命令可以筛选特定进程的CPU占用信息。

adb shell 筛选某一进程的CPU占用

adb shell dumpsys cpuinfo 命令可以展示出每一个进程的CPU占用信息,同时打印总的CPU占用信息。

adb shell 总的CPU占用、各个进程的CPU占用

3.2、CPU各核心详情

Android系统中,如果需要查看CPU各个核心的详细信息,可以使用以下命令。

// Android系统中,查看CPU各个核心的详细信息
adb shell cat /proc/cpuinfo

adb shell 查看CPU各个核心的详细信息

相关参数的详细解释如下所示:

// CPU 架构, 64bit
Processor    : AArch64 Processor rev 14 (aarch64)
// 系统中逻辑处理核的编号,0~7表示8核CPU。
processor    : 0
// 在系统内核启动时粗略测算的CPU速度(Million Instructions Per Second)
BogoMIPS    : 38.40
Features    : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
// ARM 架构
CPU implementer    : 0x51
// 8核
CPU architecture: 8
CPU variant    : 0xd
CPU part    : 0x805
CPU revision    : 14

// 品牌
Hardware    : Qualcomm Technologies, Inc LITO

四、App耗电量

App耗电量相关数据获取 与 分析可以采用以下几种方式:

  • 获取App耗电量数据:adb shell dumpsys batterystats

采用该命令,获取对应包名应用耗电量数据;

  • 分析App电量消耗:Battery-Historian分析工具

采用该分析工具,可以实现对应包名应用耗电量分析;

  • 测试进程电量消耗:perfdog(第三方工具)

https://perfdog.qq.com/article_detail?id=10089&issue_id=0&plat_id=1

4.1、获取App耗电量消耗:dumpsys batterystats

Android系统中,查看对应包名应用电量消耗数据,可以采用如下方式。

a、重置电量数据(连接数据线操作)

首先要重置电量数据(重置电量数据,所有App的电量消耗数据将清零);
然后打开全量日志数据(打开全量电量相关日志记录)。

// 重置电量数据
adb shell dumpsys batterystats --reset
// 打开全量日志记录
adb shell dumpsys batterystats --enable full-wake-history

b、APP相关场景测试(断开数据线)

重置电量数据后,需要拔掉数据线,进行相关APP场景测试

c、导出(重新连接数据线)

重新连接数据线 通过以下命令可在命令行查看对应应用的电量消耗,亦可将电量消耗信息导出到文件中

// 查看 应用电量消耗
adb shell dumpsys batterystats [应用包名] | more
// 导出 应用电量消息,这里使⽤命令more分篇查看电量相关数据
adb shell dumpsys batterystats [应用包名] >1.txt

adb shell 查看应用电量消耗

adb shell dumpsys batterystats导出的电量数据

4.2、分析App电量消耗:Battery-Historian

Battery Historain是谷歌开发的分析工具,其可以用来分析对应包名应用的耗电情况。

因本小节重点还是如何获取对应包名应用耗电相关数据,对于Battery Historain的安装与简单使用可参考我的文章
Mac 中 Battery Historain 安装与使用:
https://xiaxl.blog.csdn.net/article/details/117758299

对应包名应用耗电相关数据获取步骤如下:

a、重置电量数据(连接数据线操作)

首先要重置电量数据(重置电量数据,所有App的电量消耗数据将清零);
然后打开全量日志数据(打开全量电量相关日志记录)。

// 重置电量数据
adb shell dumpsys batterystats --reset
// 打开全量日志记录
adb shell dumpsys batterystats --enable full-wake-history

b、APP相关场景测试(断开数据线)

重置电量数据后,需要拔掉数据线,进行相关APP场景测试

c、导出(重新连接数据线)

重新连接数据线 通过以下命令导出对应应用的电量消耗数据

// Android 7.0(包含) 以上设备执行如下命令:
adb bugreport > bugreport.zip
// Android 6.0(包含) 以下设备执行如下命令:
adb bugreport > bugreport.txt

d、battery-historian 工具分析电量消耗

上一步导出的bugreport文件,上传到battery-historian 工具进行分析。

注:
国内安装Battery Historain太繁琐,主要是各种依赖包国内都下载不下来。
昨天我安装Battery Historain 一下午没搞定,后来搞到半夜一点钟 终于安装完成(中途曾几度想放弃安装,总之安装太繁琐)。
后来发现,已经有人搭建了一个Battery Historain线上环境,相关网址为: https://bathist.ef.lc/

将导出的bugreport文件上传到 https://bathist.ef.lc/ ,便可以开始应用耗电分析了。

battery-historian

4.2、测试进程电量消耗perfdog

PerfDog是腾讯研发的一款性能测试工具,可以测试某一个App对应的某一进程CPU内存电量消耗,具体操作说明:
https://perfdog.qq.com/article_detail?id=10089&issue_id=0&plat_id=1

perfdog
因为这里说的是耗电量测试,我这里举例一小时内,我写的一个测试App后台服务进程耗电量情况如下:

// 我的测试Demo后台进程,一小时耗电量如下:
Sum(Battery)[mWh]:1259.2 (1小时电量消耗)
Avg(Power)[mW]:1259.2
Avg(Voltage)[mV]:3737.7 (1小时平均电压)
Avg(Current)[mA]:337.0 (1小时平均电流)

五、参考:

使用 Battery Historian 分析耗电情况:
https://developer.android.google.cn/topic/performance/power/battery-historian?hl=zh-cn

Battery Historian GitHub地址如下:
https://github.com/google/battery-historian?spm=a2c6h.12873639.0.0.10ed5c987lIJt6

Android 调试桥 (adb)
https://developer.android.google.cn/studio/command-line/adb?hl=zh-cn

android developer dumpsys:
https://developer.android.google.cn/studio/command-line/dumpsys?hl=zh-cn

= THE END =

文章首发于公众号”CODING技术小馆“,如果文章对您有帮助,可关注我的公众号。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
1月前
|
Web App开发 监控 JavaScript
监控和分析 JavaScript 内存使用情况
【10月更文挑战第30天】通过使用上述的浏览器开发者工具、性能分析工具和内存泄漏检测工具,可以有效地监控和分析JavaScript内存使用情况,及时发现和解决内存泄漏、过度内存消耗等问题,从而提高JavaScript应用程序的性能和稳定性。在实际开发中,可以根据具体的需求和场景选择合适的工具和方法来进行内存监控和分析。
|
25天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
56 1
|
27天前
|
JavaScript
如何使用内存快照分析工具来分析Node.js应用的内存问题?
需要注意的是,不同的内存快照分析工具可能具有不同的功能和操作方式,在使用时需要根据具体工具的说明和特点进行灵活运用。
41 3
|
1月前
|
C# Windows
【Azure App Service】在App Service for Windows上验证能占用的内存最大值
根据以上测验,当使用App Service内存没有达到预期的值,且应用异常日志出现OutOfMemory时,就需要检查Platform的设置是否位64bit。
44 11
|
1月前
|
开发框架 监控 .NET
【Azure App Service】部署在App Service上的.NET应用内存消耗不能超过2GB的情况分析
x64 dotnet runtime is not installed on the app service by default. Since we had the app service running in x64, it was proxying the request to a 32 bit dotnet process which was throwing an OutOfMemoryException with requests >100MB. It worked on the IaaS servers because we had the x64 runtime install
|
1月前
|
Web App开发 JavaScript 前端开发
使用 Chrome 浏览器的内存分析工具来检测 JavaScript 中的内存泄漏
【10月更文挑战第25天】利用 Chrome 浏览器的内存分析工具,可以较为准确地检测 JavaScript 中的内存泄漏问题,并帮助我们找出潜在的泄漏点,以便采取相应的解决措施。
282 9
|
1月前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
266 1
|
20天前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
|
29天前
|
Java
JVM内存参数
-Xmx[]:堆空间最大内存 -Xms[]:堆空间最小内存,一般设置成跟堆空间最大内存一样的 -Xmn[]:新生代的最大内存 -xx[use 垃圾回收器名称]:指定垃圾回收器 -xss:设置单个线程栈大小 一般设堆空间为最大可用物理地址的百分之80
|
1月前
|
Java
JVM运行时数据区(内存结构)
1)虚拟机栈:每次调用方法都会在虚拟机栈中产生一个栈帧,每个栈帧中都有方法的参数、局部变量、方法出口等信息,方法执行完毕后释放栈帧 (2)本地方法栈:为native修饰的本地方法提供的空间,在HotSpot中与虚拟机合二为一 (3)程序计数器:保存指令执行的地址,方便线程切回后能继续执行代码
22 3