StrictMode
StrictMode
是Strict
和Mode
的合併,在英語中,strict
表示“嚴格的”,mode
表示“模式”,因此,StrictMode
就是“嚴格的模式”,或叫“嚴苛模式”,是用來檢測程序中違例情況的開發者工具。通過指定一系列策略(policy
)和對應的規則(rule
)進行檢查並且做出不同的反應,比如打印、彈窗、崩潰等。一般用來檢測主線程中的耗時操作和阻塞,諸如讀寫文件, 網絡訪問等操作以及內存泄漏。
示例
嚴格模式的開啓可以放在Application
或者Activity
以及其他組件的onCreate
方法之後super.onCreate()之前。爲了更好地分析應用中的問題,建議放在Application
的onCreate
方法中。
private void enabledStrictMode() {
if(BuildConfig.DEBUG){//調試模式下開啓
//開啓Thread策略模式
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectNetwork()//監測主線程使用網絡io
.detectCustomSlowCalls()//監測自定義運行緩慢函數
.detectDiskReads() // 檢測在UI線程讀磁盤操作
.detectDiskWrites() // 檢測在UI線程寫磁盤操作
.penaltyLog() //寫入日誌
.penaltyDialog()//監測到上述狀況時彈出對話框
.build());
//開啓VM策略模式
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects()//監測sqlite泄露
.detectLeakedClosableObjects()//監測沒有關閉IO對象
.setClassInstanceLimit(MainActivity.class, 1) // 設置某個類的同時處於內存中的實例上限,可以協助檢查內存泄露
.detectActivityLeaks()
.penaltyLog()//寫入日誌
.penaltyDeath()//出現上述情況異常終止
.build());
}
}
策略分類
StrictMode
分爲線程策略(ThreadPolicy
)和虛擬機策略(VmPolicy
)
-
線程策略
規則:
detectNetwork
:監測主線程使用網絡(重要)
detectCustomSlowCalls
:監測自定義運行緩慢函數
detectDiskReads
:檢測在UI線程讀磁盤操作 (重要)
detectDiskWrites
:檢測在UI線程寫磁盤操作(重要)
detectResourceMismatches
:檢測發現資源不匹配 (api>22)
detectAll
:檢測所有支持檢測等項目(如果太懶,不想一一列出來,可以通過這個方式)
permitDiskReads
:允許UI線程在磁盤上讀操作
permitXXX
:其他允許項類似…
permitAll
:禁用所有偵測處罰:
penaltyLog
:違規時,輸出日誌
penaltyDialog
:違規時,彈出對話框
penaltyDeath
:違規時,應用就會崩潰 -
虛擬機策略
規則:
detectActivityLeaks
:檢測Activity 的內存泄露情況(重要)(api>10)
detectCleartextNetwork
:檢測明文的網絡 (api>22)
detectFileUriExposure
:檢測file://或者是content:// (api>17)
detectLeakedClosableObjects
:檢測資源沒有正確關閉(重要)(api>10)
detectLeakedRegistrationObjects
:檢測BroadcastReceiver、ServiceConnection是否被釋放 (重要)(api>15)
detectLeakedSqlLiteObjects
:檢測數據庫資源是否沒有正確關閉(重要)(api>8)
detectAll
:檢測所有支持檢測等項目(如果太懶,不想一一列出來,可以通過這個方式)
setClassInstanceLimit
:設置某個類的同時處於內存中的實例上限,可以協助檢查內存泄露(重要)處罰:
penaltyLog
:違規時,輸出日誌
penaltyDeath
:違規時,應用就會崩潰
擴充StrictMode
在已經存在嚴格模式規則下,可以對規則進行擴充。用
getThreadPolicy()
和getVmPolicy()
獲得當前策略,用setThreadPolicy()
和setVmPolicy()
來擴充它。
StrictMode.ThreadPolicy oldThreadPolicy = StrictMode.getThreadPolicy();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(oldThreadPolicy)
.permitDiskWrites() // 在原有策略的規則基礎上,不監測讀寫磁盤
.build());
StrictMode.VmPolicy oldVmPolicy = StrictMode.getVmPolicy();
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder(oldVmPolicy)
.detectFileUriExposure() // 在原有策略的規則基礎上,監測文件URI暴露
.build());
日誌過濾
adb logcat | grep StrictMode
測試案例
下面的的代碼如果再主線程執行的話,會報Caused by: android.os.StrictMode$StrictModeViolation: policy=262175 violation=2
錯誤。根據嚴格模式,IO操作要放在工作線程當中。
public void writeToExternalStorage() {
File externalStorage = Environment.getExternalStorageDirectory();
File destFile = new File(externalStorage, "dest.txt");
OutputStream output = null;
try {
output = new FileOutputStream(destFile, true);
output.write("test".getBytes());
output.flush();
output.close();
} catch (IOException e) {
e.printStackTrace();
} finally {//我們使用流的時候,經常沒有寫finally的邏輯,當output.write出現異常會導致這個流沒有關閉。
if (null != output) {
try {//保證無論什麼情況下output流都能正常關閉
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
注意事項
- 在線上環境即
Release
版本不建議開啓嚴格模式。 - 嚴格模式無法監控
JNI
中的磁盤IO
和網絡請求。 - 應用中並非需要解決全部的違例情況,比如有些
IO
操作必須在主線程中進行。
Systrace
當我們需要確保APP的流暢度,也就是保證APP
能連續不間斷地提供每秒60
幀的運行狀態,當出現掉幀時(也可稱爲Jank
),如果我們需要知道當前整個APP
所處的狀態,Systrace
便是最佳的選擇。它能手機檢測Android
系統各個組件隨着時間的運行狀態,並能給出該如何有效地修復掉幀問題的建議。
運行Systrace
想要啓動Systrace
,需要按照下面幾個步驟:
1、啓動Android Dvice Monitor
在
Android Studio
更新之後,Android Dvice Monitor
找不到了,在Android SDK
的tools
目錄下有monitor
工具,雙擊即可啓動。
2、配置Systrace
內容
啓動分三步走:
1、選中要測試的應用:如果有異常看不到,可以重啓adb
(依次執行:adb kill-server
和adb start-server
)。
2、清除內存:避免抓取過多次trace,導致數據丟失,需要及時清除緩存中的內容。
3、啓動Systrace
:這部主要是配置需要抓取Systrace
的內容選項。
執行第三步的結果如下:
- 說明1
配置抓取systrace
的時間,通常設置5
秒,並在5
秒內重現問題,時間太短會導致問題重現時沒有被抓到,時間太長會導致JavaHeap
不夠而無法保存,因此在能抓到問題點的情況下,時間越小越好。 - 說明2
Buffer Size
是存儲systrace
的size
,同樣的,太小會導致信息丟失,時間太長會導致Java Heap
不夠而無法保存,建議20480
。 - 說明3
如果用戶有自己在應用程序中加入自己的systrace log
,如下:
那麼此處必須選擇這個應用對應的進程名字,否則新加的Trace.beginSection("tag"); Trace.endSection();
systrace log
不會被抓到。 - 說明4
這部分全部使能上。 - 說明5
針對UI相關的性能問題,以下必須使能:Bionic C Library
、CPU Frequency
、CPU Idle
、CPU load
. 如果設備可以root
,root
後可以看到更多:eMMC commands
、Synchonization
、Kernel Workqueues
等。
3、使用Chrome
分析trace
抓取的
Trace
報告提供了Android
系統進程在特定時間段內的整體情況。 例如在顯示Activity
或動畫時卡頓,Systrace
會提供關於如何解決這些問題的建議。
但是,Systrace
不會在應用程序進程中收集有關代碼執行的信息。 有關您的應用程序執行哪些方法以及使用多少CPU資源的更多詳細信息,請使用Android Studio
的內置CPUProfiler
,或生成跟蹤日誌並使用Traceview
查看它們。
我們用Chrome
瀏覽器打開,縱軸代表着時間線,事件記錄按照進程分組,同一個進程內按線程進行縱向拆分,每個線程記錄自己的工作,可收縮/展開。我們只需要關心Alerts
與Frame
兩個屬性即可。
-
Alerts(區域1)
Systrace
能自動分析trace
中的事件,並能自動高亮性能問題作爲一個Alerts
,建議調試人員下一步該怎麼做(區域4)。比如對於丟幀是,點擊黃色或紅色的Frames
圓點(區域2)便會有相關的提示信息;另外,在systrace
的最右側,有一個Alerts tab
可以展開,這裏記錄着所有的的警告提示信息(區域3)。當我們點擊了Alerts
或者點擊右邊的Alerts
列表中的任何一點我們可以看到在界面的最底部會相對應的優化提示以及可能會出現優化的視頻教程鏈接,下面會講。
-
Frame
在每個app
進程,都有一個Frames
行,正常情況以綠色的圓點表示。當圓點顏色爲黃色或者紅色時,意味着這一幀超過16.6ms
(即發現丟幀),這時需要通過放大那一幀進一步分析問題。對於Android 5.0(API level 21)
或者更高的設備,該問題主要聚焦在UI Thread
和Render Thread
這兩個線程當中。對於更早的版本,則所有工作在UI Thread
。我們可以點擊一塊Frames
中的F
點來查看,同樣的它會生成一份跟Alerts
類似的報告結果並放在界面的最低端。我們可以通過按下M
鍵查看這一幀到下一幀所花費的時間以及哪個方法被調用的最長。
常用快捷鍵
按鍵 | 描述 |
---|---|
M | 這一幀到下一幀所花費的時間 |
w | 放大 |
S | 縮小 |
A | 左移動 |
D | 右移動 |
G | 切換是否顯示60hz的網格線 |
舉例子1
findViewById(R.id.login).setOnClickListener(v -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
對於上面的代碼,Systrace
會生成一個Alert
,給出優化建議:
製作這一幀的工作被推遲了幾毫秒,造成了
jank
。確保UI線程上的代碼不會阻止在其他線程上完成的工作,並且後臺線程(例如網絡或位圖加載)在android.os.Process#thread#PRIORITY@background
或更低版本上運行,這樣它們就不太可能中斷UI
線程。這些後臺線程應該以130
或更高的優先級出現在內核進程下的調度部分。
舉例子2
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
對於上面的代碼,Systrace
會生成一個Alert
,給出優化建議:
記錄無效視圖的繪圖命令需要很長時間。避免在視圖或可繪製的自定義繪圖中進行重要工作,特別是分配或繪製到位圖。
4、使用代碼手動打trace
標籤
這個主要用在手動查看某段代碼之間的耗時。正常情況我們會在開始結束打印出系統時間,然後作減法算出耗時,但是相對比較麻煩。現在我們可以用
Trace
來手動記錄了。
Trace.beginSection("aaa");//生成的trace文件中,會在跟蹤的代碼段執行對應時間軸區間打上一個tag標記
SystemClock.sleep(1000);
SystemClock.sleep(1000);
Trace.endSection();//Trace的begin與end必須在同一線程之中執行
如果用戶有自己在應用程序中加入自己的systrace log
(如上述代碼),麼此處必須選擇這個應用對應的進程名字,否則新加的systrace log
不會被抓到。
按照以前的方法生成systrace
,在右上角查找標籤aaa
,按回車:
可以看到這段代碼的開始時間和持續時間:
如果多次調用beginSection
時,調用endSection
只會結束最近調用的beginSection
方法。 因此,對於嵌套的調用,您需要確保通過調用endSection
將每個調用正確匹配到beginSection
。
Traceview
Traceview
是Android sdk
中的一個工具,用於分析計算性能,跟蹤方法耗時導致的卡頓問題。它將Traceview
文件轉爲圖形,直觀的反應出代碼的執行時間、執行次數,便於我們分析。與前面說的systrace
的主要區別是Traceview
能顯示具體的函數的定位,而systrace不能。
1、啓動Traceview
,開始記錄
默認是1000ms採樣一次,可自行設置。點擊OK
,步驟二會變成灰色,表示開始記錄中,可以再點擊灰色按鈕結束記錄。
2、停止Traceview
點擊一次下面的按鈕即可停止記錄。
3、分析Traceview
我們在開始記錄期間,APP
要被操作起來,在操作過程中會記錄所有方法的耗時,並通過圖形化的方式展現。比如下面的代碼,問題是函數writeToExternalStorage
調用了四次耗時操作:
public void writeToExternalStorage() {
SystemClock.sleep(1000);
SystemClock.sleep(1000);
SystemClock.sleep(1000);
SystemClock.sleep(1000);
}
顯示的圖形爲:
各個參數的含義
比如上述的函數writeToExternalStorage
,調用了四次的1
秒的sleep
方法,它的Cpu Time/Cal
是7.959ms
,RealTime/Call
是4009ms
,sleep()
函數的Calls+Recur Calls/Total
是4
次。
最重要的兩個指標是Incl Cpu Time
和Calls+Recur Calls/Total
,其他的指標可以爲輔助。正常情況下我們只需要按照默認排序, 也就是Incl Cpu Time
排序, 用包名在底部"Find
“框搜索”com.yhd.structure
", 按回車一個一個查找從前往後看耗時最多的自己寫的方法,看有沒有優化的空間。還要注意調用次數過多的函數,往往可能是因爲性能問題。單擊某一個方法, 在線程列表中會抖動顯示該方法是在哪個線程上被執行的。其中Parent
表示調用這個方法的方法,可以叫做父方法,Children
表示這個方法中調用的其他方法,可以叫做子方法。
4、通過代碼生成本地.trace文件
在懷疑性能問題的代碼段外層,包裹追蹤的的殼
//低版本SDK保存文件到 "/sdcard/myTag.trace"
//高版本SDK保存到"/sdcard/Android/data/packageName/files/myTag.trace"
Debug.startMethodTracing("myTag");開始trace,
writeToExternalStorage()
Debug.stopMethodTracing();//結束
導出trace文件到電腦
adb pull /sdcard/Android/data/packageName/files/myTag.trace C:\Users\haide.yin\Desktop
打開myTag.trace文件分析
Hierarchy Viewer
Hierarchy Viewer提供了一個可視化的界面來觀測佈局的樹狀層級圖,直觀顯示測量、佈局、繪製的消耗時間,讓我們可以優化佈局層級,刪除多餘的不必要的View層級。主要用來做View層級分析, 可以分析出View Tree中的性能阻塞點, 以便對症下藥, 提升佈局性能。
1、啓動Hierarchy Viewer
2、分析頁面繪製時間
上圖紅框標出的三個點是關鍵分析數據. 左起依次代表View的Measure, Layout和Draw的性能. 另外顏色表示該View的該項時間指數, 分爲:
- 綠色:表示該
View
的此項性能比該View Tree
中超過50%的View
都要快。 - 黃色:表示該
View
的此項性能比該View Tree
中超過50%的View
都要慢。 - 紅色:表示該
View
的此項性能是View Tree
中最慢的。
會遇到的問題
- 1、打開android device monitor提示unexpected error while parsing input:Invalid ui automator hierarchy file
解決方案:只要在C:\Users\Administrator\.android
中刪除monitor-workspace
文件,重新打開monitor
就行 - 2、Could not open Selected VM debug port (8700)
解決方案1:出現這種情況是由於android studio
與DDMS
的端口衝突,所以我們可以打開DDMS
中的windows->preference->Android->DDMS
,將8600
換爲8601
,同時選中ADBHOST
,設爲127.0.0.1
,然後再將windows
系統中的host
文件中添加127.0.0.1 localhost
。
解決方案2:Android studio
也佔用了這個端口,把studio
關掉重新打開ddms
即可解決~ - 3、有時碰到模擬器或開發發版手機, view Hierarchy 還是無法連接。
解決方案:
可以先使用adb shell service call window 3
查下狀態:
Result: Parcel(00000000 00000000 '........')"
說明View Server
處於關閉狀態
Result: Parcel(00000000 00000001 '........')"
說明View Server
處於開啓狀態
使用以下命名打開View Server:
也可以使用使用以下命令關閉adb shell service call window 1 i32 4939
View Server:
adb shell service call window 2 i32 4939
- 4、有時候x86的模擬器怎麼都連不上
view Hierarchy
解決方案:換成arm鏡像的模擬器 - 5、hierarchyviewer]Unable to get view server version from device emulator-5554
解決方案:
在root
權限下cmd
執行 :adb kill-server adb start-server
- 6、真機無法連接
view Hierarchy
解決方案:
1、先把手機root
2、在進到在/system/build.prop
中添加ro.secure==0
和ro.debuggable==1
,保存重啓 - 7、無法獲取Measure、Layout、Draw的時間
解決方案:點擊右上角有三個顏色環的圖標,重新加載即可。
Android Profiler
Android Studio 3.0
及更高版本中的 Android Profiler
取代了 Android Monitor
工具。Android Profiler
工具可提供實時數據,幫助您瞭解應用的 CPU
、內存、網絡和電池資源使用情況。
要打開 Profiler
窗口,請依次選擇 View > Tool Windows > Profiler
,或者在底部工具欄選擇Profiler
,或點擊工具欄中的 Profile
圖標。
如果 Select Deployment Target
對話框提示,請選擇要在哪個設備上分析您的應用。如果您通過 USB
連接了設備但系統未列出該設備,請確保您已啓用 USB
調試。如果您使用的是 Android Emulator
或已取得 root
權限的設備,Android Profiler
將列出所有正在運行的進程,即使這些進程可能無法調試也會列出。當您啓動可調試的應用時,默認情況下會選擇該進程。Android Profiler
會持續收集分析數據,直到您斷開設備連接或點擊 End Session
。
Android Profiler 共享時間軸視圖
① Android Profiler
顯示當前正在分析的進程和設備。
② 在 Sessions
窗格中,選擇要查看的會話,或啓動一個新的分析會話。
③ 使用縮放按鈕控制要查看時間軸範圍,或使用 Attach to live
按鈕跳轉到實時更新。
④ 事件時間軸顯示與用戶輸入相關的事件,包括鍵盤 Activity
、音量控制更改和屏幕旋轉。
⑤ 共享時間軸視圖,包括 CPU
、內存、網絡和耗電量圖表。
此共享時間軸視圖只顯示時間軸圖表。包含三部分:CPU Profiler
、Memory Profiler
、Network Profiler
、Energy Profiler
。要使用詳細分析工具,請點擊與您要檢查的性能數據對應的圖表。例如,要使用相關工具檢查堆數據和跟蹤內存分配,請點擊 Memory
圖表。
並非所有分析數據在默認情況下都可見。如果您看到一條消息,顯示“Advanced profiling is unavailable for the selected process”
,您可以在運行配置中啓用高級分析以查看其他數據。
啓用高級分析
要在運行搭載 Android 7.1
或更低版本的設備時向您顯示高級分析數據,Android Studio
必須將監控邏輯注入您編譯的應用。高級分析提供的功能包括:
- 所有分析器窗口中的事件時間軸
Memory Profiler
中已分配對象的數量Memory Profiler
中的垃圾回收事件Network Profiler
中有關所有已傳輸文件的詳細信息
注意:如果您的設備搭載的是
Android 8.0
或更高版本,則默認情況下可以使用這些功能。
要啓用高級分析功能,請按以下步驟操作:
- 依次選擇
Run > Edit Configurations
。 - 在左側窗格中選擇您的應用模塊。
- 點擊
Profiling
標籤,然後勾選Enable advanced profiling
。 - 重新編譯並運行您的應用。
高級分析配置會使編譯過程變慢,所以僅在您想要開始分析您的應用時,才應啓用該配置.。
注意:高級分析功能不可用於原生代碼。如果您的應用是純原生應用(不含
Java Activity
類),則不可使用高級分析功能。如果您的應用使用JNI
,則可使用部分高級分析功能(如事件時間軸、垃圾回收事件、Java 分配對象和基於 Java 的網絡Activity
),但不能檢測基於原生代碼的分配和網絡Activity
。
Sessions會話
您可以將分析器數據另存爲會話,這些會話將一直保留,直到您退出 Android Studio。通過在多個會話中記錄分析信息並在它們之間進行切換,您可以比較各種場景中的資源使用情況。
- 要啓動一個新的會話,請點擊
Start a new profiling session
按鈕 ,然後從出現的下拉菜單中選擇一個應用進程。 - 在您記錄跟蹤記錄或捕獲堆轉儲後,
Android Studio
會將相應數據(以及您應用的網絡Activity
)作爲單獨的條目添加到當前會話。 - 要停止向當前會話添加數據,請點擊
Stop the current profiling session
圖標(如果一直不停止,時間久了會卡) 。
- 要導入之前運行
Android Studio
時導出的軌跡,請點擊Start new profiler session
圖標 ,然後選擇Load from file
。
CPU Profiler
優化應用的 CPU
使用率能帶來諸多好處,如提供更快、更順暢的用戶體驗,以及延長設備電池續航時間。您可以使用 CPU Profiler
在與應用交互時實時檢查應用的 CPU
使用率和線程活動,也可以檢查記錄的方法跟蹤數據、函數跟蹤數據和系統跟蹤數據的詳細信息。
當您打開 CPU Profiler
時,它會立即開始顯示應用的 CPU
使用率和線程活動。
① 事件時間軸:顯示應用中的 Activity
在其生命週期內不斷轉換而經歷各種不同狀態的過程,並指示用戶與設備的交互,包括屏幕旋轉事件。
② CPU 時間軸:顯示應用的實時 CPU
使用率(以佔總可用 CPU
時間的百分比表示)以及應用當前使用的線程總數。 此時間軸還會顯示其他進程(如系統進程或其他應用)的 CPU
使用率,以便您可以將其與您應用的 CPU
使用率進行對比。您可以通過沿時間軸的橫軸方向移動鼠標來檢查歷史 CPU
使用率數據。
③ 線程活動時間軸:列出屬於應用進程的每個線程,並使用下面列出的顏色在時間軸上指示它們的活動。記錄跟蹤數據後,您可以從此時間軸上選擇一個線程,以在跟蹤數據窗格中檢查其數據。
- 綠色:表示線程處於活動狀態或準備使用
CPU
。也就是說,線程處於正在運行或可運行狀態。 - 黃色:表示線程處於活動狀態,但它正在等待一項
I/O
操作(如磁盤或網絡I/O
),然後才能完成它的工作。 - 灰色:表示線程處於休眠狀態並且沒有佔用任何
CPU
時間。 當線程需要訪問尚不可用的資源時,就會出現這種情況。在這種情況下,要麼線程主動進入休眠狀態,要麼內核將線程置於休眠狀態,直到所需的資源可用。
CPU Profiler
還會報告Android Studio
和Android
平臺添加到應用進程的線程的CPU
使用率,這些線程包括JDWP
、Profile Saver
、Studio:VMStats
、Studio:Perfa
和Studio:Heartbeat
等(不過,它們在線程活動時間軸上顯示的確切名稱可能有所不同)。Android Studio
將報告此數據,以便您確定什麼時候線程活動和CPU
使用率實際上是由您的應用的代碼引發的。
選擇記錄配置
-
對 Java 方法採樣(Sample Java Methods):在應用的
Java
代碼執行期間,頻繁捕獲應用的調用堆棧。分析器會比較捕獲的數據集,以推導與應用的Java
代碼執行有關的時間和資源使用信息。基於採樣的跟蹤存在一個固有的問題,那就是如果應用在捕獲調用堆棧後進入一個方法並在下次捕獲前退出該方法,分析器將不會記錄該方法調用。如果您想要跟蹤生命週期如此短的方法,應使用檢測跟蹤。
-
跟蹤 Java 方法(Trace Java Methods):在運行時檢測應用,以在每個方法調用開始和結束時記錄一個時間戳。系統會收集並比較這些時間戳,以生成方法跟蹤數據,包括時間信息和
CPU
使用率。請注意,與檢測每個方法相關的開銷會影響運行時性能,並且可能會影響分析數據;對於生命週期相對較短的方法,這一點更爲明顯。此外,如果應用在短時間內執行大量方法,則分析器可能很快就會超出其文件大小限制,因而不能再記錄更多跟蹤數據。
-
對 C/C++ 函數採樣(Sample C/C+ Functions):捕獲應用的原生線程的採樣跟蹤數據。
要使用此配置,您必須將應用部署到搭載
Android 8.0
(API
級別26
)或更高版本的設備上。 -
跟蹤系統調用(Trace System Calls):捕獲非常翔實的細節,以便您檢查應用與系統資源的交互情況。您可以檢查線程狀態的確切時間和持續時間、直觀地查看所有內核的
CPU
瓶頸在何處,並添加要分析的自定義跟蹤事件。 當您排查性能問題時,此類信息至關重要。要使用此配置,您必須將應用部署到搭載
Android 7.0
(API
級別24
)或更高版本的設備上。使用此跟蹤配置時,您可以通過檢測代碼,在分析器時間軸上直觀地標記重要的代碼例程。要檢測C/C++
代碼,請使用由trace.h
提供的原生跟蹤API
。要檢測Java
代碼,請使用Trace
類。如需瞭解詳情,請參閱檢測您的應用代碼。此跟蹤配置建立在systrace
的基礎之上。您可以使用systrace
命令行實用程序指定除CPU Profiler
提供的選項之外的其他選項。systrace
提供的其他系統級數據可幫助您檢查原生系統進程並排查丟幀或幀延遲問題。
記錄跟蹤數據
要開始記錄跟蹤數據,請從 CPU Profiler
頂部的下拉菜單中選擇記錄配置,然後點擊 Record
。與您的應用交互,然後在完成時點擊 Stop
。分析器將自動選擇記錄的時間範圍,並在跟蹤數據窗格中顯示其跟蹤信息,如圖所示。如果要檢查其他線程的跟蹤數據,請從線程活動時間軸上選擇相應線程。
① 選定範圍:確定要在跟蹤數據窗格中檢查所記錄時間的哪一部分。當您首次記錄跟蹤數據時,CPU Profiler
會自動在 CPU
時間軸上選擇記錄的完整長度。 要僅檢查已記錄的時間範圍中的一部分的跟蹤數據,請拖動突出顯示區域的邊緣。
② 時間戳:指示所記錄跟蹤數據的開始和結束時間(相對於分析器開始收集 CPU
使用率信息的時間)。要選擇完整的記錄,請點擊時間戳。
③ 跟蹤數據窗格:顯示您選擇的時間範圍和線程的跟蹤數據。此窗格要在您至少記錄一條跟蹤數據後纔會顯示。 在此窗格中,您可以選擇如何查看每個堆棧軌跡(使用跟蹤數據標籤頁),以及如何測量執行時間(使用時間參考下拉菜單)。
④ 跟蹤數據窗格標籤頁:選擇如何顯示跟蹤數據詳細信息。如需詳細瞭解各個選項,請參閱檢查跟蹤數據。
⑤ 時間參考菜單:選擇以下選項之一,以確定如何測量每次調用的時間信息:
- Wall clock time:該時間信息表示實際經過的時間。
- Thread time:該時間信息表示實際經過的時間減去線程沒有佔用
CPU
資源的那部分時間。對於任何給定的調用,其線程時間始終小於或等於其掛鐘時間。使用線程時間可以讓您更好地瞭解線程的實際CPU
使用率中有多少是給定方法或函數佔用的。
⑥ 過濾器:按函數、方法、類或軟件包名稱過濾跟蹤數據。例如,如果您要快速識別與特定調用相關的跟蹤數據,請點擊 Filter
圖標 或按 Ctrl + F
(在 Mac
上,按 Command + F
鍵),然後在搜索字段中輸入相應的名稱。在 Call chart
和 Flame chart
標籤頁中,會突出顯示包含符合搜索查詢條件的調用、軟件包或類的調用堆棧。在 Top down
和 Bottom up
標籤頁中,這些調用堆棧優先於其他跟蹤結果。您還可以通過勾選搜索字段旁邊的相應方框來啓用以下選項:
- Regex:要在您的搜索中包含正則表達式,請使用此選項。
- Match case:如果您的搜索區分大小寫,請使用此選項。
檢查跟蹤數據
CPU Profiler
中的跟蹤數據窗格提供多個標籤頁,供您選擇如何查看所記錄的跟蹤數據中的信息。要查看方法跟蹤數據和函數跟蹤數據,您可以從 Call Chart
、Flame Chart
、Top Down
和 Bottom Up
標籤頁中進行選擇。要查看系統跟蹤數據(Trace System Calls
),您可以從 Trace Events
、Flame Chart
、Top Down
和 Bottom Up
標籤頁中進行選擇。
Call Chart
Call Chart
標籤頁會以圖形來呈現方法跟蹤數據或函數跟蹤數據,其中調用的時間段和時間在橫軸上表示,而其被調用方則在縱軸上顯示。對系統 API
的調用顯示爲橙色,對應用自有方法的調用顯示爲綠色,對第三方 API
(包括 Java
語言 API
)的調用顯示爲藍色。下圖顯示了一個調用圖表示例,說明了給定方法或函數的 Self
時間、Children
時間和 Total
時間的概念(下面會講)。
提示:要跳轉到某個方法或函數的源代碼,雙擊或者右鍵點擊該方法或函數,然後選擇
Jump to Source
。在跟蹤數據窗格的任意標籤頁中都可以執行此操作。
Flame Chart
Flame Chart
標籤頁提供一個倒置的調用圖表,用來彙總完全相同的調用堆棧。也就是說,將具有相同調用方順序的完全相同的方法或函數收集起來,並在火焰圖中將它們表示爲一個較長的橫條(而不是將它們顯示爲多個較短的橫條,如調用圖表中所示)。這樣更方便您查看哪些方法或函數消耗的時間最多。不過,這也意味着,橫軸不代表時間軸,而是表示執行每個方法或函數所需的相對時間。
爲幫助說明此概念,不妨考慮下圖的調用圖表。請注意,方法 D
多次調用 B
(B1
、B2
和 B3
),其中一些對 B
的調用也調用了 C
(C1
和 C3
)。
由於 B1
、B2
和 B3
具有相同的調用方順序 (A
→ D
→ B
),因此係統將它們彙總在一起,如下圖所示。同樣,也將 C1
和 C3
彙總在一起,因爲它們也具有相同的調用方順序 (A
→ D
→ B
→ C
)。請注意,C2
不包括在內,因爲它具有不同的調用方順序 (A
→ D
→ C
)。
彙總的調用用於創建火焰圖,如下圖所示。 請注意,對於火焰圖中的任何給定調用,佔用最多 CPU
時間的被調用方最先顯示。
Top Down和Bottom Up
Top Down
標籤顯示一個調用列表,在該列表中展開方法或函數節點會顯示它的被調用方。下圖顯示了上面的調用圖表的自上而下圖。圖中的每個箭頭都是從調用方指向被調用方。在 Top Down
標籤頁中展開方法 A
的節點會顯示它的被調用方,即方法 B
和 D
。在此之後,展開方法 D
的節點會顯示它的被調用方,即方法 B
和 C
,依此類推。
圖 9. 圖 8 中方法 C 的“Bottom Up”樹。
Bottom Up
標籤頁顯示一個調用列表,在該列表中展開函數或方法的節點會顯示它的調用方。下圖提供了方法 C
的“Bottom Up
”樹。在該“Bottom Up
”樹中打開方法 C
的節點會顯示它獨有的各個調用方,即方法 B
和 D
。請注意,儘管 B
調用 C
兩次,但在“Bottom Up
”樹中展開方法 C
的節點時,B
僅顯示一次。在此之後,展開 B
的節點會顯示它的調用方,即方法 A
和 D
。
Bottom Up
標籤頁用於按照佔用的 CPU
時間由多到少(或由少到多)的順序對方法或函數排序。您可以檢查每個節點以確定哪些調用方在調用這些方法或函數上所花的 CPU
時間最多。 與“Top Down
”樹相比,“Bottom Up
”樹中每個方法或函數的時間信息參照的是每個樹頂部的方法(頂部節點)。 CPU
時間也可表示爲在該記錄期間佔線程總時間的百分比。下表說明了如何解讀頂部節點及其調用方(子節點)的時間信息。
節點類型 | Self | Children | Total |
---|---|---|---|
Bottom Up 樹頂部的方法或函數(頂部節點) |
表示方法或函數在執行自己的代碼(而非被調用方的代碼)上所花的總時間。與Top Down 樹相比,此時間信息表示在記錄的持續時間內對此方法或函數的所有調用時間的總和。 |
表示方法或函數在執行它的被調用方(而非自己的代碼)上所花的總時間。與Top Down 樹相比,此時間信息表示在記錄的持續時間內對此方法或函數的被調用方的所有調用時間的總和 |
Self 時間和 Children 時間的總和。 |
調用方(子節點) | 表示被調用方在由調用方調用時的總 Self 時間。以上圖的Bottom Up 樹爲例,方法 B 的 Self 時間將等於每次執行由方法 B 調用的方法 C 所用的 Self 時間的總和。 |
表示被調用方在由調用方調用時的總 Children 時間。以上圖的Bottom Up 樹爲例,方法 B 的 Children 時間將等於每次執行由方法 B 調用的方法 C 所用的 Children 時間的總和。 |
Self 時間和 Children 時間的總和。 |
注意:對於給定的記錄,當分析器達到文件大小限制時,
Android Studio
會停止收集新數據(不過,不會停止記錄)。在執行檢測跟蹤時,這種情況通常發生得更快,因爲與採樣跟蹤相比,此類跟蹤會在更短的時間內收集更多的數據。如果您將檢查時間範圍延長至達到限制後的記錄時段,則跟蹤數據窗格中的時間數據不會發生變化(因爲沒有新數據可用)。此外,當您僅選擇沒有可用數據的那部分記錄時,對於時間信息,跟蹤數據窗格將顯示NaN
。
Trace Events
檢查系統跟蹤數據時,您可以使用 Trace Events
標籤查看每個線程上發生的事件的詳細信息。要查看某個線程的詳細信息,請在 Threads
窗格中選擇該線程。這樣將在 Kernel
窗格中突出顯示該線程在每個 CPU
內核上的活動,並在 Trace Events
標籤頁中顯示該線程的事件。在 Trace Events
標籤頁中將鼠標指針懸停在某個事件上可查看該事件的名稱以及在每種狀態下所用的時間。
您可以檢查應用在主線程和 RenderThread
上渲染每個幀所用的時間,以調查造成界面卡頓和幀速率低的瓶頸。要查看幀渲染數據,請使用可讓您跟蹤系統調用的配置記錄跟蹤數據。記錄跟蹤數據後,在名爲 FRAMES
的部分下查找有關每個幀的信息,每個用時超過 16 毫秒的幀都以紅色顯示。如何檢查系統跟蹤信息,來源於上文提到的 systrace
。
其他功能
除了上述提到的功能,你也可以使用 Debug API
記錄 CPU 活動。這個功能我們在上文中提到。當您的應用調用 startMethodTracing(String tracePath)
時,CPU Profiler
將開始記錄;當您的應用調用 stopMethodTracing()
時,CPU Profiler
將停止記錄。在記錄使用此 API
觸發的 CPU
活動時,CPU Profiler
會將 Debug API
顯示爲作用中的 CPU
記錄配置。
您可以將相應數據導出爲 .trace
文件,您可以導入使用 Debug API
或 CPU Profiler
創建的 .trace
文件。
Memory Profiler
Memory Profiler
是 Android Profiler
中的一個組件,可幫助您識別可能會導致應用卡頓、凍結甚至崩潰的內存泄露和內存抖動。它顯示一個應用內存使用量的實時圖表,讓您可以捕獲堆轉儲、強制執行垃圾回收以及跟蹤內存分配。
爲什麼應分析您的應用內存
Android
提供了託管內存環境 - 當它確定您的應用不再使用某些對象時,垃圾回收器會將未使用的內存釋放回堆中。雖然 Android
查找未使用內存的方式在不斷改進,但對於所有 Android
版本,系統都必須在某個時間點短暫地暫停您的代碼。大多數情況下,這些暫停難以察覺。不過,如果您的應用分配內存的速度比系統回收內存的速度快,則當回收器釋放足夠的內存以滿足您的分配需要時,您的應用可能會延遲。此延遲可能會導致您的應用跳幀,並使系統明顯變慢,也就是內存抖動現象。
儘管您的應用不會表現出變慢,但如果存在內存泄露,則即使應用在後臺運行也會保留該內存。此行爲會強制執行不必要的垃圾回收事件,因而拖慢系統其餘部分的內存性能。最後,系統被迫終止您的應用進程以回收內存。然後,當用戶返回您的應用時,它必須完全重啓。
爲幫助防止這些問題,您應使用 Memory Profiler
執行以下操作:
- 在時間軸上查找可能會導致性能問題的不理想的內存分配模式。
- 轉儲 Java 堆以查看在任何給定時間哪些對象耗盡了內存。在很長一段時間內進行多次堆轉儲有助於識別內存泄露。
- 記錄正常用戶交互和極端用戶交互期間的內存分配,以準確識別您的代碼在何處短時間內分配了過多對象,或分配了泄露的對象。
當您首次打開 Memory Profiler
時,您將看到一條表示應用內存使用量的詳細時間軸,並可使用各種工具來強制執行垃圾回收、捕獲堆轉儲以及記錄內存分配。
① 用於強制執行垃圾回收事件的按鈕。
② 用於捕獲堆轉儲的按鈕。
注意:只有在連接到搭載
Android 7.1
(API
級別25
)或更低版本的設備時,纔會在堆轉儲按鈕右側顯示用於記錄內存分配的按鈕。
③ 用於指定分析器多久捕獲一次內存分配的下拉菜單。選擇適當的選項可幫助您 在分析時提高應用性能。
④ 用於縮放時間軸的按鈕。
⑤ 用於跳轉到實時內存數據的按鈕。
⑥ 事件時間軸,顯示活動狀態、用戶輸入事件和屏幕旋轉事件。
⑦ 內存使用量時間軸,它會顯示以下內容:
- 一個堆疊圖表,顯示每個內存類別當前使用多少內存,如左側的
y
軸以及頂部的彩色鍵所示。 - 一條虛線,表示分配的對象數,如右側的
y
軸所示。 - 每個垃圾回收事件的圖標。
如何計算內存
您在 Memory Profiler
頂部看到的數字基於您的應用根據 Android 系統機制所提交的所有私有內存頁面。此計數不包含與系統或其他應用共享的頁面。
-
Java:從
Java
或Kotlin
代碼分配的對象的內存。 -
Native:從
C
或C++
代碼分配的對象的內存。即使您的應用中不使用
C++
,您也可能會看到此處使用的一些原生內存,因爲Android
框架使用原生內存代表您處理各種任務,如處理圖像資源和其他圖形時,即使您編寫的代碼採用Java
或Kotlin
語言。 -
Graphics:圖形緩衝區隊列向屏幕顯示像素(包括
GL
表面、GL
紋理等等)所使用的內存。(請注意,這是與CPU
共享的內存,不是GPU
專用內存。) -
Stack:您的應用中的原生堆棧和
Java
堆棧使用的內存。這通常與您的應用運行多少線程有關。 -
Code:您的應用用於處理代碼和資源(如
dex
字節碼、經過優化或編譯的dex
代碼、.so
庫和字體)的內存。 -
Others:您的應用使用的系統不確定如何分類的內存。
-
Allocated:您的應用分配的
Java/Kotlin
對象數。此數字沒有計入C
或C++
中分配的對象。如果連接到搭載
Android 7.1
及更低版本的設備,只有在Memory Profiler
連接到您運行的應用時,纔開始此分配計數。因此,您開始分析之前分配的任何對象都不會被計入。不過,Android 8.0
及更高版本附帶一個設備內置分析工具,該工具可跟蹤所有分配,因此,在Android 8.0
及更高版本上,此數字始終表示您的應用中待處理的Java
對象總數。
查看內存分配
內存分配爲您顯示內存中的每個 Java
對象和 JNI
引用是如何分配的。具體而言,Memory Profiler
可爲您顯示有關對象分配的以下信息:
- 分配了哪些類型的對象以及它們使用多少空間。
- 每個分配的堆棧軌跡,包括在哪個線程中。
- 對象在何時被取消分配(僅當使用搭載
Android 8.0
或更高版本的設備時)。
如果您的設備搭載的是 Android 8.0
或更高版本,您可以隨時查看對象分配,具體操作步驟如下:在時間軸上拖動以選擇要查看哪個區域的分配。不需要開始記錄會話,因爲 Android 8.0
及更高版本附帶設備內置分析工具,可持續跟蹤您的應用分配。
如果您的設備搭載的是 Android 7.1
或更低版本,請點擊 Memory Profiler
工具欄中的 Record memory allocations
圖標 。記錄時,Memory Profiler
會跟蹤您的應用中發生的所有分配。完成後,請點擊 Stop recording
圖標以查看分配。
選擇時間軸的某個區域後(或者使用搭載 Android 7.1
或更低版本的設備完成記錄會話後),已分配對象的列表將顯示在時間軸下方,按類名稱進行分組,並按其堆計數排序。
注意:在 Android 7.1 及更低版本上,您最多可以記錄 65535 個分配。 如果您的記錄會話超出此限制,則記錄中僅保存最新的 65535 個分配。(在 Android 8.0 及更高版本上,則沒有實際的限制。)
要檢查分配記錄,請按以下步驟操作:
- 瀏覽列表以查找堆計數異常大且可能存在泄露的對象。爲幫助查找已知類,點擊
Class Name
列標題以按字母順序排序。然後,點擊一個類名稱。此時右側將出現Instance View
窗格,顯示該類的每個實例。此外,您也可以快速找到對象,方法是點擊Filter
圖標 ,或按Ctrl+F
鍵(在Mac
上,按Command+F
鍵),然後在搜索字段中輸入類或軟件包名稱。如果從下拉菜單中選擇Arrange by callstack
,還可以按方法名稱搜索。如果要使用正則表達式,請勾選Regex
旁邊的複選框。如果您的搜索查詢區分大小寫,請勾選Match case
旁邊的複選框。 - 在
Instance View
窗格中,點擊一個實例。此時下方將出現Call Stack
標籤頁,顯示該實例被分配到何處以及在哪個線程中。 - 在
Call Stack
標籤頁中,右鍵點擊任意行並選擇Jump to Source
,以在編輯器中打開該代碼。
從左側的菜單中,選擇要檢查的堆:
- default heap:當系統未指定堆時。
- image heap:系統啓動映像,包含啓動期間預加載的類。此處的分配保證絕不會移動或消失。
- zygote heap:寫時複製堆,其中的應用進程是從
Android
系統中派生的。 - app heap:您的應用在其中分配內存的主堆。
- JNI heap:顯示 Java 原生接口 (
JNI
) 引用被分配和釋放到什麼位置的堆。
從右側的菜單中,選擇如何安排分配:
- Arrange by class:根據類名稱對所有分配進行分組。這是默認選項。
- Arrange by package:根據軟件包名稱對所有分配進行分組。
- Arrange by callstack:將所有分配分組到其對應的調用堆棧。
在分析時提高應用性能
爲了在分析時提高應用性能,Memory Profiler
在默認情況下會定期對內存分配進行採樣。在運行 API
級別 26
或更高級別的設備上進行測試時,您可以使用 Allocation Tracking
下拉菜單來更改此行爲。可用選項如下:
- Full:捕獲內存中的所有對象分配。這是
Android Studio 3.2
及更低版本中的默認行爲。如果您有一個分配了大量對象的應用,則可能會在分析時觀察到應用的運行速度明顯減慢。 - Sampled:定期對內存中的對象分配進行採樣。這是默認選項,在分析時對應用性能的影響較小。在短時間內分配大量對象的應用仍可能會表現出明顯的速度減慢。
- Off:停止跟蹤應用的內存分配。
查看全局 JNI 引用
Java
原生接口 (JNI
) 是一個允許 Java
代碼和原生代碼相互調用的框架。
JNI
引用由原生代碼進行管理,因此原生代碼使用的 Java
對象可能會保持活動狀態太長時間。如果丟棄了 JNI
引用而未先明確將其刪除,Java
堆上的某些對象可能會變得無法訪問。此外,還可能會達到全局 JNI
引用限制。
要排查此類問題,請使用 Memory Profiler
中的 JNI heap
視圖來瀏覽所有全局 JNI
引用,並按 Java
類型和原生調用堆棧對其進行過濾。藉助此信息,您可以瞭解創建和刪除全局 JNI
引用的時間和位置。
捕獲堆轉儲(Dump Java Heap)
堆轉儲顯示在您捕獲堆轉儲時您的應用中哪些對象正在使用內存。特別是在長時間的用戶會話後,堆轉儲會顯示您認爲不應再位於內存中卻仍在內存中的對象,從而幫助識別內存泄露。
捕獲堆轉儲後,您可以查看以下信息:
- 您的應用分配了哪些類型的對象,以及每種對象有多少。
- 每個對象當前使用多少內存。
- 在代碼中的什麼位置保持着對每個對象的引用。
- 對象所分配到的調用堆棧。(目前,對於
Android 7.1
及更低版本,只有在記錄分配期間捕獲堆轉儲時,纔會顯示調用堆棧的堆轉儲。)
要捕獲堆轉儲,請點擊 Memory Profiler
工具欄中的 Dump Java heap
圖標 。 在轉儲堆期間,Java
內存量可能會暫時增加。 這很正常,因爲堆轉儲與您的應用發生在同一進程中,並需要一些內存來收集數據。堆轉儲出現在內存時間軸下方,顯示堆中的所有類類型,如圖:
在類列表中,您可以查看以下信息:
- Allocations:堆中的分配數。
- Native Size:此對象類型使用的原生內存總量(以字節爲單位)。只有在使用
Android 7.0
及更高版本時,纔會看到此列。 您會在此處看到採用Java
分配的某些對象的內存,因爲Android
對某些框架類(如Bitmap
)使用原生內存。 - Shallow Size:此對象類型使用的 Java 內存總量(以字節爲單位),不包括它引用的對象。
- 針對非數組類型的對象,它的大小就是對象與它所有的成員變量大小的總和。當然這裏面還會包括一些java語言特性的數據存儲單元,比如
alignment
位數對齊。 - 針對數組類型的對象,它的大小是數組元素對象的大小總和。
- 針對非數組類型的對象,它的大小就是對象與它所有的成員變量大小的總和。當然這裏面還會包括一些java語言特性的數據存儲單元,比如
- Retained Size:爲此類的所有實例而保留的內存總大小(以字節爲單位)。
Retained Size
是指, 當實例被回收時, 可以同時被回收的實例的Shallow Size之
和。所以進行內存分析時, 我們應該重點關注Retained Size
較大的實例; 或者可以通過Retained Size
判斷出某實例內部使用的實例是否被其他實例引用。例如在Android中, 如果某個Bitmap
實例的Retained Size
很小, 證明它內部的byte
數組被複用了, 有另一個Bitmap
實例指向了同一個byte
數組。換句話說,Retained Size
就是當前對象被GC
後,從Heap
上總共能釋放掉的內存。不過,釋放的時候還要排除被其他對象直接或間接引用的對象。
點擊一個類名稱可在右側打開 Instance View
窗口。列出的每個實例都包含以下信息:
- Depth:從任意 GC 根到選定實例的最短跳數。
這個參數非常重要,只有Depth = 0 的時候對象才能被回收。當我們在頁面銷燬的時候執行
Dump Java Heap
,發現某個應該銷燬的對象的Depth
不爲0
,那麼證明該對象存在泄露。 - Native Size:原生內存中此實例的大小。 只有在使用
Android 7.0
及更高版本時,纔會看到此列。 - Shallow Size:Java 內存中此實例的大小。
- Retained Size:此實例所支配內存的大小。
其他
我們可以將堆轉儲另存爲 HPROF
文件,也可以導入一個 HPROF (.hprof)
文件。
Network Profiler
Network Profiler
會在時間軸上顯示實時網絡活動,包括髮送和接收的數據以及當前的連接數。這便於您檢查應用傳輸數據的方式和時間,並適當優化底層代碼。
目前,
Network Profiler
僅支持HttpURLConnection
和OkHttp
網絡連接庫。如果您的應用使用的是其他網絡連接庫,您可能無法在Network Profiler
中查看網絡活動。如果 Network Profiler 檢測到流量值,但無法識別任何受支持的網絡請求,您會收到以下錯誤消息:Network Profiling Data Unavailable:There is no information for the network traffic you've selected.
爲什麼應分析應用的網絡活動
當您的應用向網絡發出請求時,設備必須使用高功耗的移動或 WLAN 無線裝置來收發數據包。無線裝置不僅要消耗電力來傳輸數據,而且還要消耗額外的電力來開啓並且不鎖定屏幕。
使用 Network Profiler
,您可以查找頻繁出現的短時網絡活動峯值,這些峯值意味着,您的應用要求經常開啓無線裝置,或要求無線裝置長時間不鎖定屏幕以處理集中出現的大量短時請求。這種模式說明您可以通過批量處理網絡請求,減少必須開啓無線裝置來發送或接收數據的次數,從而優化應用,改善電池性能。這種方式還能讓無線裝置切換到低功耗模式,延長批量處理請求之間的間隔時間,節省電量。
概覽
窗口頂部顯示的是事件時間軸。在時間軸 (①) 上,您可以點擊並拖動以選擇時間軸的一部分來檢查網絡流量。
在時間軸下方的窗格 (②) 中,您可以選擇以下某個標籤頁,以詳細瞭解時間軸上選定時段內的網絡活動:
- Connection View:列出了在時間軸上選定時段內從您應用的所有
CPU
線程發送或接收的文件。對於每個請求,您可以檢查大小、類型、狀態和傳輸時長。 您可以通過點擊任意列標題來對此列表排序。您還會看到時間軸上選定時段的明細數據,從而瞭解每個文件的發送或接收時間。 - Thread View:顯示您應用的每個
CPU
線程的網絡活動。 如下圖所示,您可以在此視圖中檢查應用的哪些線程負責每個網絡請求。
從 Connection View
或 Thread View
中,點擊請求名稱可檢查有關已發送或已接收數據的詳細信息 (③)。點擊各個標籤頁可查看響應標頭和正文、請求標頭和正文或調用堆棧。
在 Response
和 Request
標籤頁中,點擊 View Parsed
鏈接可顯示格式化文本,點擊 View Source
鏈接可顯示原始文本。
注意:如果您使用的是
HttpURLConnection API
,則不會在Request
標籤頁中看到標頭,除非您使用setRequestProperty
方法將其添加到您的代碼中:urlConnection.setRequestProperty("Accept-Encoding", "identity");
Energy Profiler
Energy Profiler
可幫助您瞭解應用在哪裏耗用了不必要的電量;會監控 CPU
、網絡無線裝置和 GPS
傳感器的使用情況,並直觀地顯示其中每個組件消耗的電量; 還會顯示可能會影響耗電量的系統事件(喚醒鎖定、鬧鐘、作業和位置信息請求)的發生次數。Energy Profiler
並不會直接測量耗電量,而是使用一種模型來估算設備上每項資源的耗電量。
概覽
當您在搭載 Android 8.0 (API 26)
或更高版本的關聯設備或 Android
模擬器中運行您的應用時,Energy Profiler
便會顯示爲 Profiler
窗口中的一個新行。當您打開 Energy Profiler
時,它會立即開始顯示應用的估算耗電量。
Energy Profiler 的默認視圖包括以下時間軸:
① Event時間軸:顯示應用中的 Activity
在其生命週期內不斷轉換而經歷各種不同狀態的過程。此時間軸還會指示用戶與設備的交互,包括屏幕旋轉事件。
② Energy時間軸:顯示應用的估算耗電量。
③ System時間軸:顯示可能會影響耗電量的系統事件。
要查看 CPU、網絡和位置信息 (GPS) 資源,以及相關係統事件的具體耗電量情況,請將鼠標指針放在 Energy 時間軸中的條形上方。
檢查系統事件:喚醒鎖定、作業和鬧鐘
您可以使用 Energy Profiler 查找可能會影響耗電量的系統事件,包括喚醒鎖定、作業和鬧鐘:
- 喚醒鎖定是一種機制,可在設備進入休眠模式時使
CPU
或屏幕保持開啓狀態。例如,播放視頻的應用可以使用喚醒鎖定,以便在用戶未與設備交互時使屏幕保持開啓狀態。請求喚醒鎖定不是一項耗電量很高的操作,但未撤消喚醒鎖定會導致屏幕或CPU
保持開啓狀態的時間超過必要時間,從而加快電池耗電速度。 - 您可以使用鬧鐘定期在應用上下文之外運行後臺任務。當鬧鐘觸發時,它可能會喚醒設備並運行耗電量很高的代碼。
- 您可以使用作業在指定條件下(例如恢復網絡連接時)執行相關操作。您可以使用
JobBuilder
創建作業,並使用JobScheduler
對這些作業進行調度。在許多情況下,建議您使用JobScheduler
對作業進行調度,而不是使用鬧鐘或喚醒鎖定。 - 位置信息請求使用 GPS 傳感器,這會消耗大量電量。
藉助 Energy Profiler
,您可以輕鬆找到應用使用各項功能的位置,以便您就如何使用各項功能做出明智的決策。Energy Profiler
會在 Energy
時間軸下的 System
時間軸中顯示一個彩色編碼的條形,以表示系統事件處於活動狀態的時間範圍。喚醒鎖定用紅色條形表示,作業和鬧鐘用黃色條形表示,位置信息事件用淺紫色條形表示。
下圖顯示了 Energy Profiler
,並在代碼編輯器中定位到了未釋放喚醒鎖定對應的源代碼。
① 要打開 System Event 窗格並顯示喚醒鎖定等事件的詳細信息,請在 Energy 時間軸中選擇一個時間範圍。
② 要打開 Wake Lock Details 窗格並顯示特定喚醒鎖定的詳細信息,請在 System Event 窗格中選擇該喚醒鎖定。
③ 要打開代碼編輯器並跳轉到喚醒鎖定的源代碼,請在 Wake Lock Details 窗格中雙擊調用堆棧頂部的調用方法條目。
④ 用於獲取喚醒鎖定的調用會在源代碼編輯器中突出顯示。
Leakcanary
Square
出品,必屬精品。類似與APP
探針的內存泄露監測工具,不用寫任何代碼就能引入APP
的內存泄漏檢測機制,這裏不做深入。