分析Handler引發的內存泄漏

分析工具

android studio

當前使用版本:android studio 3.4
android studio 提供了Profiler工具可以提供可視化的內存觀察,以及堆轉儲的功能。在實際使用過程中感覺太繁瑣,因爲我們沒法確定是哪個頁面發生了內存泄漏,所以就引用了LeakCanary

2.LeakCanary

當前使用版本:com.squareup.leakcanary:leakcanary-android:1.6.3
引用官方的一句話"A memory leak detection library for Android",LeakCanary能幫我們動態監控內存泄漏,以及發生在哪個頁面,同時還能自動的完成堆轉儲

3.MAT

當前使用版本:Eclipse Memory Analyzer Version 1.8.1
引用官方的一句話"The Eclipse Memory Analyzer is a fast and feature-rich Java heap analyzer that helps you find memory leaks and reduce memory consumption.",MAT是一個功能強大的Java堆分析器

內存泄漏代碼

  • MainActivity
 @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      findViewById(R.id.btn_no_static_class).setOnClickListener(v -> startActivity(new Intent(MainActivity.this, NoStaticClassActivity.class)));
  }
  • NoStaticClassActivity
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_no_static_class);
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, Thread.currentThread().getName());
            }
        }, 1000 * 60 * 10);
        finish();
    }

分析

  • LeakCanary自動捕獲到了信息:


這個Demo比較簡單,其實通過LeakCanary就可以分析出問題出現在什麼地方,當內容比較複雜時LeakCanary並沒有那麼直觀的看出內存泄漏的原因,還是需要使用MAT工具

  • MAT分析.hprof文件
    LeakCanary會自動的將泄漏信息保存到手機的\Download\leakcanary-xxxx\目錄下,將該目錄下的.hprof文件複製到電腦,這個文件還不能直接用MAT工具打開,需要執行下面的一段命令,轉換成能正常打開的文件
hprof-conv.exe .\2019-05-16_11-13-28_699.hprof handle.hprof

將轉換好的handle.hprof文件使用MAT打開就會看見下面界面



然後點擊用紅色圈圈起來的Histigram,會看到下面的界面



然後在紅色框中輸入我們要分析的類名,在LeakCanary的界面中已經很明確的知道是NoStaticClassActivity這個類發生了泄漏,所以在框中輸入NoS點擊回車就會列來,右鍵點擊我們搜索出來的類名

點擊後就會跳轉到下面界面



這樣我們就非常明確的看到了Thread持有了NoStaticClassActivity的應用,從中可以看到有MessageQueue,Message會很快想到和Handler有關,然後在分析具體代碼。

解決之後的代碼

  • NoStaticClassActivity
 private final Handler mHandler = new MyHandle();
 private static class MyHandle extends Handler{
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    }

在去點擊按鈕發現內存泄漏已經被我們修復了,本文重要的是說明工具的使用,代碼有不嚴謹的地方請諒解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章