項目GitHub
本文要點
- 一般使用的卡頓優化工具
- 卡頓問題概述
- 卡頓問題分析難點
- 關於CPU Profiler
- 關於Systrace
- 關於StrictMode
- 磁盤讀寫違例檢測實戰
- 實例限制檢測實戰
一般使用的卡頓優化工具
- CPU Profiler
- Systrace
- StrictMode
(strict adj.精確的; 絕對的; 嚴格的,嚴謹的; [植]筆直的
mode n.方式; 狀況; 時尚,風尚; 調式 模式;)
卡頓問題概述
- 很多性能問題(如內存佔用高、耗費流量等)都相對不容易被發現,
但是卡頓問題卻是很容易被直觀感受到的; - 卡頓問題較難排查、定位;
卡頓問題分析難點
- 可能的產生原因 繁雜:代碼、內存、繪製、IO、【在主線程做UI處理、IO操作耗時操作】等;
- 線上卡頓問題,在線下難以復現,
卡頓問題跟用戶屆時的現場環境有很大的關係; - 比如,
屆時用戶終端的磁盤IO空間不足,影響了APP的IO寫入性能,
導致APP卡頓,這樣的場景有時候是很難復現的;
【最好在問題發生時候,就記錄下來用戶屆時的場景】
關於CPU Profiler
圖形的形式展示程序的執行時間、調用棧、執行次數等;
信息全面,包含了所有線程、所有方法的調用時間;
運行時開銷比較嚴重,導致APP運行時所有函數都會不等比地變慢,可能會帶偏優化方向;
-
使用方式
-
Debug.startMethodTracing();
【在需要監控的代碼塊
前添加(注意它有四個重載方法)】 -
Debug.stopMethodTracing();
【在需要監控的代碼塊
後添加】 - 生成的調試文件在sd卡:Android/data/packagename/files
- 上次在內存優化的實戰中,
其實已經使用過,提到過CPU Profiler了,
這裏可以看一下App內存優化 之 內存抖動解決實戰!!!!!!
-
關於Systrace
監控和
跟蹤Api調用
、線程運行
情況,生成Html報告
;需要在API 18以上使用,推薦TraceCompat;
-
使用方式
python systrace.py -t 10 [other-options][categories]
- 可以參考CSDN某博客;
或Android性能優化 -- Systrace工具(有option或category的參數表格) - 輕量級,開銷小
- 直觀反映CPU利用率
- 給出建議
關於StrictMode
嚴苛模式,Android提供的一種運行時檢測機制;
如果在開發階段對成千上萬行的代碼進行code review,
可能效率是比較低下的;
使用StrictMode之後,
系統會自動檢測
出來主線程當中違例
的一些情況,
同時按照代碼的配置
給出相應的反應
。方便,強大,容易被忽視
-
主要檢測:線程檢測策略、虛擬機檢測策略
- 線程檢測策略【
StrictMode.setThreadPolicy()
】:
如,
自定義的耗時調用檢測,如detectCustomSlowCalls()
;
磁盤讀取操作檢測,detectDiskReads()
網絡操作檢測,detectNetwork()
【detect vt.查明,發現; 洞察; 偵察,偵查; 】 - 虛擬機策略【
StrictMode.setVmPolicy()
】:
Activity泄漏檢測,detectActivityLeaks()
SqlLite對象泄漏檢測,detectLeakedSqlLiteObjects()
限制實例數量檢測,setClassInstanceLimit(要限制的類實例,限制的數量)
- 線程檢測策略【
具體使用:
可以在Activity
或者Application
的onCreate()
中調用StrictMode的方法:
private boolean DEV_MODE = true;
private void initStrictMode() {
if (DEV_MODE) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectCustomSlowCalls() //API等級11,使用StrictMode.noteSlowCode
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()// or .detectAll() for all detectable problems
.penaltyLog() //在Logcat 中打印違規異常信息
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.setClassInstanceLimit(NewsItem.class, 1)
.detectLeakedClosableObjects() //API等級11
.penaltyLog()
.build());
}
}
【調試技巧】
設置一個DEV_MODE
標誌位:
只有在線下開發的環境時將之設置爲true,纔會使進程打開StrictMode
;【檢測策略的調用】
detect開頭的方法,
都是StrictMode提供的檢測策略,
調用過了,則StrictMode
便會進行相應的檢測和反應;-
【響應方式配置】
penaltyLog()
【penalty n.懲罰,刑罰,害處】是出現違規後用log打印出來,即指定StrictMode
的響應方式,StrictMode
除了打印log的方式,
還有其他響應方式,
如penaltyDeath()
可以讓APP直接崩潰掉,penaltyDialog()
可以彈出一個Dialog等!!!!!!!!! 實戰一下:
磁盤讀寫違例檢測(log的響應方式
):
/**
* 模擬內存泄露的Activity
*/
public class MemoryLeakActivity extends AppCompatActivity implements CallBack{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_memoryleak);
ImageView imageView = findViewById(R.id.iv_memoryleak);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.splash);
imageView.setImageBitmap(bitmap);
CallBackManager.addCallBack(this);
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.penaltyLog()
.build());
findViewById(R.id.iv_memoryleak).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
writeToExternalStorage();
}
});
}
/**
* 文件系統的操作
*/
public void writeToExternalStorage() {
try {
File externalStorage = Environment.getExternalStorageDirectory();
File mbFile = new File(externalStorage, "xxx.txt");
if (mbFile.exists()){
mbFile.createNewFile();
}
OutputStream output = new FileOutputStream(mbFile, true);
output.write("www.wooyun.org".getBytes());
output.flush();
output.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
CallBackManager.removeCallBack(this);
}
@Override
public void dpOperate() {
// do sth
}
}
Dialog
的響應方式:以上IO違例的原因就是
在主線程做了IO操作了
,
這顯然是不行的,需要開一個子線程給它整!
-
實例限制檢測:
public class TestApp extends Application {
static MemoryLeakActivity i = new MemoryLeakActivity();
static MemoryLeakActivity j = new MemoryLeakActivity();
@Override
public void onCreate() {
super.onCreate();
//實例限制檢測 測試
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.setClassInstanceLimit(MemoryLeakActivity.class, 1)
.detectLeakedClosableObjects() //API等級11
.penaltyLog()
.build());
}
}