檢測工具
- AndroidStudio3.0以上
- Memory analyzer或者eclipse MAT插件
1.準備工作:
首先我們模擬內存泄漏,如下代碼:
ToastUtils.java
public class ToastUtils {
private static final ToastUtils ourInstance = new ToastUtils();
private static Context mContext;
public static ToastUtils getInstance(Context context) {
mContext =context;
return ourInstance;
}
private ToastUtils() {
}
public void showToast(String msg){
Toast.makeText(mContext,msg,Toast.LENGTH_SHORT).show();
}
}
Main2Activity
public class Main2Activity extends AppCompatActivity {
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
ToastUtils.getInstance(this).showToast("hahahhaha");
handler.sendEmptyMessageDelayed(1,6000);
}
}
2.開始檢測
2.1以Android Profiler運行應用程序,點擊如下按鈕
Android Profiler
2.2選擇MEMORY,點擊如下按鈕
MEMORY
2.3開始進行測試,隨便點點我們的應用然后點擊下圖1按鈕請求gc,再點擊2獲取一份內存快照,如下:
獲取內存快照
2.4分析生成的文件,生成的文件如下圖:
內存快照
- Alloc Cout 對象數
- Shallow Size 對象占用內存大小
- Retained Set 對象引用組占用的內存
注:如果Alloc Cout 數量不是1的話,可能就發生了內存泄漏
2.4點擊保存到本地,文件名為1.hprof
保存到本地
2.5使用hprof-conv命令轉成標準的mat文件
命令如下:
hprof-conv -z /Users/cool/me/1.hprof /Users/cool/me/1_mat.hprof
如果找不到hprof-conv命令,請配置一下環境變量,hprof-con為/SDK/platform-tools/下的工具
將1_mat.hprof拖到 Memory analyzer中,或者已安裝mat插件的eclipse中
如下:
mat
點擊紅框中的按鈕,再根據泄漏的類名Main2Activity來篩選,
image.png
回車,得到下面結果
image.png
選中要排查的類,排除軟弱虛引用
image.png
將得到結果全部展開,如下:
image.png
分析此圖,我們看到有3個泄漏點,因為內存泄漏是自己模擬的,所以我們很快就能定位到問題,這里假裝是真實開發的項目,我們一個一個分析:
- 第一個泄漏點:沿著Main2Activity一直往上追溯,會發現GCRoot為 com.cool.skinresource.ToastUtils,這里的代碼寫的有問題,打開后發現單例中靜態引用Activity實例導致gc無法回收
- 第二個泄漏點:仔細看就知道handler機制導致的內存泄漏,非靜態內部類持有外部類Activity的引用導致的
*第三個泄漏點:Toast的內部類mNextView,mView持有了Activity的引用,這里是因為靜態的Context才導致的,如果需要解決此泄漏,需要通過反射將mNextView,mView置為null,將引用鏈打破即刻
將問題解決后再重復此步驟檢測,直至沒有內存泄漏