背景
前段时间自己摸索着做了一些Android性能测试,现在告一段落,是时候整理一下笔记了。回顾自己期间学到的东西,顺便规划下后续深入学习的方向。
性能关注点
- 渲染: 过度绘制、布局冗杂
-
资源消耗:
CPU
、内存
- 功耗: 流量、耗电
今天我们主要关注CPU和内存,其他的留着后面继续学习。
测试方法
内存和CPU测试主要是为了检测应用在用户不同使用强度下消耗手机内存和CPU的情况,如果内存消耗过大会造成手机使用时卡顿,闪退等现象,进而影响用户体验,甚至会影响日活数据和用户留存等情况。因此,应用的内存占用大小也是产品体验好坏一个重要指标和测试重点。正常情况下,应用不应占用过多的内存资源,且能够及时释放内存,保证整个应用内的稳定性和流畅性。根据手机的使用应用频度和强度不同,可将应用使用强度分为如下几种状态:
- 空闲状态:指启动应用后,不做任何操作或切换到后台运行的情况称为空闲状态。
- 中规格状态:指后台已经有几个应用在运行,已经并且消耗了系统的一些资源的情况。
- 满规格状态:该种情况为应用内高频率的使用,用户很少达到,跑monkey时可认为高强度状态,该种情况常用来测试应用内存泄漏的情况测试时,可根据用户的操作习惯模拟应用使用频率和强度等级。
一、使用adb命令
使用adb有很多种获取cpu和内存的命令,这里我只说我用的顺手的,想要了解更多的,动动你的小手自己网上查去吧~
相关结果说明参考:https://blog.csdn.net/wirelessqa/article/details/29187517
查看CPU占用率
-
a. dumpsys获取实时cpu占用率
adb shell dumpsys cpuinfo | grep <PackageName>
示例:
defu@DefuTaideMacBook-Pro $ adb shell dumpsys cpuinfo | egrep 'com.zmsoft.kds: ' 3.4% 32159/com.zmsoft.kds: 2.9% user + 0.4% kernel / faults: 286 minor # 说明:应用CPU占用率3.4%,其中用户占用2.9%,内核占用0.4%
-
b. top持续监控cpu占用率
adb shell top -d 0.1 | grep <PackageName>
示例:
defu@DefuTaideMacBook-Pro $ adb shell top -h Usage: top [ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [ -t ] [ -h ] -m num Maximum number of processes to display. // 最多显示多少个进程 -n num Updates to show before exiting. // 刷新次数 -d num Seconds to wait between updates. // 刷新间隔时间(默认5秒) -s col Column to sort by (cpu,vss,rss,thr). // 按哪列排序 -t Show threads instead of processes. // 显示线程信息而不是进程 -h Display this help screen. // 显示帮助文档 defu@DefuTaideMacBook-Pro $ adb shell top -m 5 -s cpu User 1%, System 1%, IOW 0%, IRQ 0% User 17 + Nice 4 + Sys 14 + Idle 1175 + IOW 0 + IRQ 0 + SIRQ 2 = 1212 PID PR CPU% S #THR VSS RSS PCY UID Name 423 2 0% S 79 813500K 54112K fg system system_server 32159 2 0% S 117 897396K 108204K fg u0_a69 com.zmsoft.kds 13869 3 0% R 1 1284K 484K root top 101 0 0% S 15 73560K 2996K fg system /system/bin/surfaceflinger 476 2 0% S 23 730980K 34500K fg u0_a5 com.android.systemui # 结果说明: # CPU占用率: # User 用户进程 # System 系统进程 # IOW IO等待时间 # IRQ 硬中断时间 # CPU使用情况(指一个最小时间片内所占时间,单位jiffies。或者指所占进程数): # User 处于用户态的运行时间,不包含优先值为负进程 # Nice 优先值为负的进程所占用的CPU时间 # Sys 处于核心态的运行时间 # Idle 除IO等待时间以外的其它等待时间 # IOW IO等待时间 # IRQ 硬中断时间 # SIRQ 软中断时间 # 进程属性: # PID 进程在系统中的ID # CPU% 当前瞬时所以使用CPU占用率 # S 进程的状态,其中S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值是负数。 # #THR 程序当前所用的线程数 # VSS Virtual Set Size 虚拟耗用内存(包含共享库占用的内存) # RSS Resident Set Size 实际使用物理内存(包含共享库占用的内存) # PCY OOXX,不知道什么东东 # UID 运行当前进程的用户id # Name 程序名称android.process.media
-
c. 通过Java代码获取
/** * 获取正在运行时APP的CPU的使用情况,获取失败返回0 * 返回单位:百分比 * * @return */ public static int getProcessCpuRate(String packageName) { int cpuUse = 0; try { String Result; Process processCpuRate = Runtime.getRuntime().exec("adb shell dumpsys cpuinfo | grep " + packageName); BufferedReader processCpuRateInput = new BufferedReader(new InputStreamReader(processCpuRate.getInputStream(),"GB2312")); while ((Result = processCpuRateInput.readLine()) != null) { if (Result.length() < 1) { continue; } else { String CPUusr = Result.split("%")[0]; cpuUse = Integer.valueOf(GetPhoneInfo.getSUM(CPUusr.substring(CPUusr.length() - 3))); return cpuUse; } } processCpuRateInput.close(); } catch (IOException e) { LogUtil.logger().error("Adb 文件不存在!"); e.printStackTrace(); } return cpuUse; }
获取内存使用量
-
a. dumpsys查看内存
adb shell dumpsys meminfo <PackageName>
示例:
defu@DefuTaideMacBook-Pro ~ adb shell dumpsys meminfo com.zmsoft.kds Applications Memory Usage (kB): Uptime: 2493701465 Realtime: 2493701448 ** MEMINFO in pid 32159 [com.zmsoft.kds] ** Pss Private Private Swapped Heap Heap Heap Total Dirty Clean Dirty Size Alloc Free ------ ------ ------ ------ ------ ------ ------ Native Heap 0 0 0 0 40556 27546 457 Dalvik Heap 28306 28228 0 0 29852 28886 966 Dalvik Other 9516 9372 0 0 Stack 24 24 0 0 Ashmem 2 0 0 0 Other dev 9 0 8 0 .so mmap 11233 6796 3540 0 .apk mmap 402 0 160 0 .ttf mmap 1506 0 1176 0 .dex mmap 15527 1352 11572 0 Other mmap 234 16 164 0 Unknown 19409 19400 0 0 TOTAL 86168 65188 16620 0 70408 56432 1423 Objects Views: 1306 ViewRootImpl: 4 AppContexts: 7 Activities: 4 Assets: 2 AssetManagers: 2 Local Binders: 32 Proxy Binders: 30 Death Recipients: 2 OpenSSL Sockets: 4 SQL MEMORY_USED: 851 PAGECACHE_OVERFLOW: 335 MALLOC_SIZE: 62 DATABASES pgsz dbsz Lookaside(b) cache Dbname 4 384 459 14908/711/25 /mnt/internal_sd/kds/rcdebug/master/data/db/kdsmaster.db 4 24 500 26/40/12 /mnt/internal_sd/kds/gadebug/db/kds.db # 参数含义: # VSS – Virtual Set Size 虚拟耗用内存(包含共享库占用的内存) # RSS – Resident Set Size 实际使用物理内存(包含共享库占用的内存) # PSS – Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存) # USS – Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存) # // ps:内存占用大小有如下规律:VSS >= RSS >= PSS >= USS # // PSS Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存) # // USS Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存) 其中,USS需要设备root后才能获取,没有root过的设备获取PSS即可(PSS获取方法:adb shell dumpsys meminfo <PackageName> | grep TOTAL)。USS是应用启动时占用的虚拟内存,杀掉进程即会释放。
-
b. 通过Java代码获取内存信息
/** * 获取APP运行占用的内存,获取失败返回0 * 返回单位:K * * @return */ public static int getRunMemin(String packageName) { int memin = 0; try { String Result; Process p = Runtime.getRuntime().exec("adb shell dumpsys meminfo " + packageName); BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), "GB2312")); while ((Result = br.readLine()) != null) { if (Result.length() < 1) { continue; } else { if (Result.contains(AppiumAndroidTest.appPackage)) { memin = Integer.parseInt(GetPhoneInfo.getSUM(Result.split(":")[0])); return memin; } } } br.close(); } catch (IOException e) { // TODO Auto-generated catch block LogUtil.logger().error("Adb 文件不存在!"); e.printStackTrace(); } return memin; }
二、使用Android Studio自带的Android Profiler性能分析工具
前提条件:
- Android系统版本必须5.1.1以上
- 设备连接电脑(adb connect连接 or 数据线连接)
Android Studio -> view -> Android Profiler
内存计数中的类别如下所示:
- Java:从 Java 或 Kotlin 代码分配的对象内存。
- Native:从 C 或 C++ 代码分配的对象内存。
- Graphics:图形缓冲区队列向屏幕显示像素(包括 GL 表面、GL 纹理等等)所使用的内存。 (请注意,这是与 CPU 共享的内存,不是 GPU 专用内存。)
- Stack: 您的应用中的原生堆栈和 Java 堆栈使用的内存。 这通常与您的应用运行多少线程有关。
- Code:您的应用用于处理代码和资源(如 dex 字节码、已优化或已编译的 dex 码、.so 库和字体)的内存。
- Other:您的应用使用的系统不确定如何分类的内存。
- Allocated:您的应用分配的 Java/Kotlin 对象数。 它没有计入 C 或 C++ 中分配的对象。