背景
前段時間自己摸索著做了一些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
圖1 - CPU Profiler
圖2 - Memory Profiler
圖3 - Memory Profiler 頂部內存計數圖例
內存計數中的類別如下所示:
- Java:從 Java 或 Kotlin 代碼分配的對象內存。
- Native:從 C 或 C++ 代碼分配的對象內存。
- Graphics:圖形緩沖區隊列向屏幕顯示像素(包括 GL 表面、GL 紋理等等)所使用的內存。 (請注意,這是與 CPU 共享的內存,不是 GPU 專用內存。)
- Stack: 您的應用中的原生堆棧和 Java 堆棧使用的內存。 這通常與您的應用運行多少線程有關。
- Code:您的應用用于處理代碼和資源(如 dex 字節碼、已優化或已編譯的 dex 碼、.so 庫和字體)的內存。
- Other:您的應用使用的系統不確定如何分類的內存。
- Allocated:您的應用分配的 Java/Kotlin 對象數。 它沒有計入 C 或 C++ 中分配的對象。