摘要:相對的在性能優化方面,相當于將的功能集成到了中。手機連接電腦后運行應用,在中會看到以下視圖左上角可以選擇設備和進程,點擊區域,即可進入視圖左上角可以選擇跟蹤模式按默認采樣率捕獲應用的調用堆棧。
前言
性能優化的過程分兩部分:
發現性能瓶頸
制定方案,解決性能問題
解決性能問題的方案需要具體情況具體分析,并沒有完全固定的路子,更多的是靠經驗的積累,本文不做涉及。但是發現性能瓶頸確實有著固定的方法。本文主要介紹 如何找到性能瓶頸 。
如何找到性能瓶頸
常用的性能檢測工具是traceview,集成于 Android Device Monitor 中。從Android Studio3.0開始, Android Device Monitor 被廢棄,取而代之的是 Android Profiler ,其中提供了 Memory Prodiler 、CPU Profiler、Network Prodiler三大功能。
內存優化(包括內存泄漏)常用的是 MAT 或者 LeakCanary ,而 Memory Profiler 相當于將 MAT 的簡化版功能集成到 AS 中。相對的在性能優化方面,CPU Profiler 相當于將 traceview 的功能集成到了 AS 中。
所以,使用AS3.0之前版本的,可以使用traceview,而使用AS3.0以后版本的,除了traceview,還可以選擇CPU Profiler。
如果想追蹤系統進程的詳細數據,以解決幀引起的界面卡頓等問題,可以使用 systrace ,本文不做涉及。
traceview 使用方法
使用 traceview 需要首先使用 Debug 類進行 插樁 ,當應用執行到被插樁的代碼時就會在手機sdcard中自動生成 .trace 文件,之后使用 traceview 或者 AS(3.0以上版本)打開文件即可。
一、插樁
插樁需要使用到 Debug 類,并且會在 sdcard 中生成 .trace 文件,所以你必須首先保證你的應用具有寫外部存儲( WRITE_EXTERNAL_STORAGE )的權限。
在想要跟蹤的代碼邏輯開頭和結尾處分別插樁:
// Starts recording a trace log with the name you provide. For example, the
// following code tells the system to start recording a .trace file to the
// device with the name "sample.trace".
Debug.startMethodTracing("sample");
...
// The system begins buffering the generated trace data, until your
// application calls stopMethodTracing(), at which time it writes
// the buffered data to the output file.
Debug.stopMethodTracing();
生成的 .trace 文件會被保存在固定目錄下,與 getExternalFilesDir() 返回的目錄相同,即 /sdcard/Android/data/[YOUR_PACKAGE_NAME]/files 下。
請注意,如果您的應用在未更改跟蹤日志名稱的情況下再次調用 startMethodTracing(),則會覆蓋已保存至設備的現有日志。如果希望每次運行都保存至不同的日志文件,可以使用如下代碼:
// Uses the SimpleDateFormat class to create a String with
// the current date and time.
SimpleDateFormat date =
new SimpleDateFormat("dd_MM_yyyy_hh_mm_ss");
String logDate = date.format(new Date());
// Applies the date and time to the name of the trace log.
Debug.startMethodTracing(
"sample-" + logDate);
如果系統在您調用 stopMethodTracing() 之前達到最大緩沖值,則會停止跟蹤并向管理中心發送通知。 開始和停止跟蹤的函數在您的整個應用流程內均有效。 也就是說,您可以在 Activity 的 onCreate(Bundle)
函數中調用 startMethodTracing(),在 Activity 的 onDestroy() 函數中調用 stopMethodTracing()。
二、查看 .trace 文件
插好樁后,安裝應用并運行被檢測部分的功能,然后就可以通過 AS 或者 traceview 查看文件了。
使用 AS 查看
在AS中點擊 View - Tool Windows - Android File Explorer 打開 Android File Explorer :
在 /sdcard/Android/data/[YOUR_PACKAGE_NAME]/files 下即可找到生成的 .trace 文件,雙擊文件即可打開。
將 .trace 文件保存至電腦,直接拖入AS窗口,也可直接打開該視圖。
在打開的視圖中,左上方可以選擇想要查看的線程??梢圆榭幢O控期間指定線程運行了多久、執行了哪些方法、每個方法執行了多久等等。
其中有4個名詞需要解釋一下:
Wall Clock Time:壁鐘時間,表示實際經過的時間,即進入某個方法到退出該方法的時間,不考慮線程是活動還是休眠狀態。
Thread time:線程時間,表示實際經過的時間減去線程沒有消耗 CPU 資源(處于休眠)的時間部分。 對于任何給定函數,其線程時間始終少于或等于其壁鐘時間。 使用線程時間可以讓您更好地了解線程的實際 CPU 使用率中有多少是給定函數消耗的。
Inclusive Time:方法執行自己代碼的時間 + 執行自己child方法的時間。
Exclusive Time:方法執行自己代碼的時間。
使用 traceview 查看
要使用 traceview 查看,需要首先將 .trace 文件保存到電腦:
adb pull /sdcard/Android/data/[YOUR_PACKAGE_NAME]/files/sample.trace D:Documentssample.trace
打開 Android Device Monitor 。AS3.0以前的版本,就是LogCat所在的窗口,再切換一下tab頁即可。AS3.0以后,進入 android-sdk/tools/ 路徑,運行以下命令:
monitor
雖然 Android Device Monitor 的 DDMS 也有 File Explorer ,但是未 root 的手機,查看不到上述路徑,因此只能將 .trace 文件保存到電腦查看。
在 Android Device Monitor 中,依次點擊 File - Open File ,選擇 .trace 文件路徑即可打開:
內容與AS打開時類似,相差較大的主要是圖標部分,沒有AS的 Call Chart 直觀形象。
其中也有4個概念:
Cpu Time:相當于AS中的 Thread time。
Real Time:相當于AS中的Wall Clock Time。
Inclusive Time:同AS一樣。
Exclusive Time:同AS一樣。
使用 AS 查看還是使用 traceview 查看
這個就見仁見智了,根據我個人使用的感覺來看,建議使用AS查看。原因有二:
AS更簡單。不需要多帶帶打開ADM,更不需要將 .trace 文件保存到電腦。
AS的調用圖( Call Chart )更加直觀,cpu時間的消耗一目了然。
Call Chart 的水平軸表示函數調用(或調用方)的時間段和時間,并沿垂直軸顯示其被調用者。 下圖展示了一個調用圖表示例,并描繪了給定函數的 self time、children time 以及總時間的概念。
最后需要注意一點,跟蹤分析過程中,應用的運行速度會減慢。所以,通過 traceview 得到的分析數據并不能精確反應某個方法在實際執行時的絕對時間。關于這一點,在最后的注意事項中再做詳細分析。
Google還提供了基于樣本的分析方式,以減少分析對運行時性能的影響。要啟用樣本分析,需調用 Debug.startMethodTracingSampling() 方法(而非 Debug.startMethodTracing() 方法)。系統會定期收集樣本,直至調用 stopMethodTracing() 。
CPU Profiler 使用方法
使用 CPU Profiler 進行函數跟蹤比 traceview 更簡單。不需要做任何代碼上的植入,下面做一個簡單的介紹:
首先,通過
View - Tool Windows - Android Profiler 打開 Android Profiler 。手機連接電腦后運行應用,在 Android Profiler 中會看到以下視圖:
左上角可以選擇設備和進程,點擊 CPU 區域,即可進入CPU Profiler視圖:
左上角可以選擇跟蹤模式:
Sampled:按默認采樣率捕獲應用的調用堆棧。該模式的固有問題是,如果應用在一次捕獲后進入一個函數并在下一次捕獲前退出該函數,則分析器不會記錄該函數調用。如果對此類生命周期很短的跟蹤函數感興趣,可以使用“Instrumented”跟蹤。
Instrumented:以在每個函數調用的開始和結束時記錄時間戳。 分析比較時間戳,以生成函數跟蹤數據。 需要注意的是,設置與函數關聯的開銷會影響運行時性能,甚至分析數據,對于生命周期相對較短的函數,這一點更為明顯。 此外,如果應用短時間內執行大量函數,則分析器可能會迅速超出它的文件大小限制,且不能再記錄更多跟蹤數據。
Edit configurations:自定義采樣率。與 traceview 中的 Debug.startMethodTracingSampling() 類似。
.trace 文件的大小是有限制的。對于給定錄制,當分析器到達該限制時,AS 將停止收集新數據(不過,這不會停止記錄)。 在執行“Instrumented”跟蹤時,這種情況通常會更快發生,因為與“Sampled”跟蹤相比,此類跟蹤在較短時間里會收集更多數據。
如果你使用的是Android 8.0(API 26)或更高版本的設備,則對于跟蹤數據的文件大小沒有限制,此值可忽略。不過,你仍需留意每次記錄后設備收集了多少數據,因為 AS 可能難以解析大型跟蹤文件。
點擊上方的“開始錄制”按鈕,然后在應用中操作執行被追蹤的功能,結束后再點擊“停止錄制”按鈕。CPU Profiler 會自動開始分析并生成數據。
以上就是 CPU Profiler 和 traceview 的使用方法。至于如何制定優化方案,就不展開了,并沒有完全固定的路子。就我本例的 onRebuild() 方法而言,是針對耗時的Contact構造過程做了并行處理,將上百個有序的構造過程平分到5個線程中并發執行,然后再按順序合并數據到一個線程中。最終 onRebuild() 執行速度從15秒提升到了2.5秒,對我來說已經夠用了。
重要注意事項
無論是使用 traceview 還是 CPU Profiler 進行函數跟蹤,有一點需要注意:跟蹤分析過程中,應用的運行速度會減慢。所以,分析數據并不能精確反應某個方法在實際執行時的絕對時間。下面是我在優化項目中的 onRebuild(boolean) 方法時,記錄的4組數據,讓我們來對比一下:
實際執行時間:不啟用分析模式,正常運行狀態下通過打印日志得到的實際執行時間。
Profiler統計時間:使用 CPU Profiler 分析獲得的執行時間。
traceview統計時間:通過分析 traceview 產生的 .trace 文件,從中獲得的執行時間。
traceview實際時間:使用 traceview 的情況下,通過打印日志得到的實際執行時間。
為什么針對 traceview 會例舉兩個時間呢?這是因為測試過程中發現 traceview 自動分析出來的時間比 實際執行時間 不僅沒有慢,反而快了很多,疑惑下又在啟用 traceview 的情況下通過以下代碼測算了一下實際的時間,這個倒是真的比 實際執行時間 慢了。
Debug.startMethodTracing("smssdk_onrebuild");
long curr = System.currentTimeMillis();
onRebuild(true);
Log.d(TAG, "onRebuild lasts: " + (System.currentTimeMillis() - curr));
Debug.stopMethodTracing();
從上表數據可見,無論是 CPU Profiler 還是 traceview ,
統計出來的時間都不能準確代表實際執行時間。更甚者,traceview自動分析出來的數據也與traceview跟蹤模式下實際的時間有巨大差別,關于這一點,我沒找到詳細的解釋,如果有人知道,還望不吝賜教。
既然跟蹤分析得到的時間都不能表示實際的時間,那么這些數據是不是沒用呢?當然不是!它們至少在以下兩個方面具有價值:
在一次檢測得到的數據中,線程內各個方法執行所耗時間在整個線程執行時間中所占比例具有一定參考價值。占比高的方法當是優化的重點目標。
優化前后兩次檢測得到的數據,有比較價值,以確認優化方案是否真的生效。
通過這些工具跟蹤函數,也只能做一個相對的參考,并不能完全正確的反應函數的執行性能。比如我通過 CPU Profiler 獲得的 onRebuild() 方法的分析數據顯示,整個執行過程中 Contact 的構造方法占了60%左右,Contact.toString() 方法占了40%左右,但實際上在 onRebuild() 方法消耗的15秒中,Contact.toString() 只消耗了百毫秒級,而九成以上時間都被其構造方法消耗了,說明 CPU Profiler 的監控過程對 Contact.toString() 的性能產生了更大的影響。
而同樣的問題卻并沒有出現在 traceview 的分析結果中。
請注意,CPU Profiler 和 traceview 不能同時使用,如果代碼中植入了插樁的代碼,則有可能導致 CPU Profiler 無法正常開始或停止錄制。
traceview 和 CPU Profiler 的對比
從用法上來看,traceview 比 CPU Profiler 稍微復雜一點。類似于MAT需要首先獲取 .hprof 堆轉儲文件,traceview 也要首先獲取 .trace 文件,然后使用traceview分析該文件。而 CPU Profiler 則可以直接對應用進行分析。
從最終生成的圖表上來看,CPU Profiler 生成的圖表有 Call Chart、Flame Chart ,它們可以非常形象的表示出線程內執行了哪些函數,函數的執行時間,調用棧等等,一目了然,而且在任意函數上點擊右鍵,可以直接跳轉至對應的代碼,非常方便,在這一點上,相對于 traceview 要優秀。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/103110.html
摘要:不努力不奮斗,可能就會在基層一輩子止步不前。不過,只一句,如果你還在做這一行,還是一名程序猿媛,想走上坡路的你,也許我這到手的十幾家一線互聯網公司性能優化項目實戰可能會對你有所幫助。 ...
摘要:昨天有個小學弟給我發來微信,說他現在有點后悔選擇開發了,月月光不說,還加班特別嚴重,平時也沒有屬于自己的時間去學習,問我剛畢業的時候是不是這樣。每天回到出租屋都是倒頭就睡,非常累,也沒有其他時間提升自己的技術。 昨天有個小學弟給我發來微信,說他現在有點后悔選擇Android開發了,月月光不說...
閱讀 1003·2023-04-25 14:20
閱讀 1879·2021-11-24 10:20
閱讀 3783·2021-11-11 16:55
閱讀 2928·2021-10-14 09:42
閱讀 3478·2019-08-30 15:56
閱讀 1180·2019-08-30 15:55
閱讀 1077·2019-08-30 15:44
閱讀 787·2019-08-29 11:28