天天看點

Android性能優化-記憶體洩漏(下) 如何進行記憶體洩漏的分析

如何進行記憶體洩漏的分析

使用Android Studio Monitors

AndroidMonitors是Android Studio自帶的功能,我們可以通過裡面的Memory子產品來進行記憶體洩漏的分析,平時開發我們也可以通過該子產品來觀察記憶體的抖動情況。

Android性能優化-記憶體洩漏(下) 如何進行記憶體洩漏的分析

這裡我們首先知道,标注1是進行GC的操作,标注2是進行Dump操作,也就是可以生成我們瞬時的堆記憶體快照,我們主要也是通過分析堆記憶體的快照來進行記憶體洩漏分析。

一般我們先進行幾次gc操作,待記憶體平穩後,執行dump操作。會生成一個phrof的記憶體快照

Android性能優化-記憶體洩漏(下) 如何進行記憶體洩漏的分析

此時我們可以看到幾個面闆:

  1. ClassName:堆記憶體中存在的類
  2. Instaance:類存在的執行個體
  3. ReferenceTree:持有該類的引用

幾個屬性的含義:

  1. Depth:引用的層級
  2. Shallow Size:對象的大小(Byte)
  3. Dominating Size:釋放該對象能節省的堆記憶體(Byte)

将快照轉換為Mat能夠導入的格式

在as的captures中可以右鍵選擇export to standard .hprof 将快照轉換為mat能夠帶入的檔案格式

Android性能優化-記憶體洩漏(下) 如何進行記憶體洩漏的分析

使用MAT

MAT是一款功能更強大的記憶體洩漏分析工具,在實際的記憶體分析中,我們可以結合Monitors進行記憶體洩漏分析。

下載下傳位址http://www.eclipse.org/mat/

Android性能優化-記憶體洩漏(下) 如何進行記憶體洩漏的分析

導入快照後,我們可以通過Histogram檢視記憶體快照

Android性能優化-記憶體洩漏(下) 如何進行記憶體洩漏的分析

在Histogram中,我們可以通過篩選過濾出我們項目中的包和類,這個操作實際中很有用。

Android性能優化-記憶體洩漏(下) 如何進行記憶體洩漏的分析

選中具體的對象後,右鍵list objects--with incoming references可以檢視對改對象持有的應用

Android性能優化-記憶體洩漏(下) 如何進行記憶體洩漏的分析

我們可以看到,這個時候引用還是非常的,我們需要過濾一些無用的軟引用之類的。通過右鍵-megre shortest path to GC roots-exclude all phantom/sofe/weak etc.refrences進行過濾,這個時候基本就能查出我們自己寫的代碼的引用

Android性能優化-記憶體洩漏(下) 如何進行記憶體洩漏的分析

另外Mat還支援2個快照進行比對,這個功能也是非常有用的。

我們可以在Navigation History中選擇 Histogram,然後右鍵選擇Add to compare basket加入比較選項,将2個快照的Histogram加入後在compare basket欄中點選紅色感歎号就可以執行快照的比對。

Android性能優化-記憶體洩漏(下) 如何進行記憶體洩漏的分析

使用leakcanary

Square開源了一個記憶體洩露自動探測神器——LeakCanary,它是一個Android和Java的記憶體洩露檢測庫,可以大幅度減少了開發中遇到的OOM問題。

github https://github.com/square/leakcanary

通過官方的文檔介紹,我們可以輕松在項目內建

加入依賴:

dependencies {
   debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
   releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
   testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
 }
           

Application 配置:

public class ExampleApplication extends Application {

  ......
  //在自己的Application中添加如下代碼
public static RefWatcher getRefWatcher(Context context) {
    ExampleApplication application = (ExampleApplication) context
            .getApplicationContext();
    return application.refWatcher;
}

  //在自己的Application中添加如下代碼
private RefWatcher refWatcher;

@Override
public void onCreate() {
    super.onCreate();
    ......
        //在自己的Application中添加如下代碼
    refWatcher = LeakCanary.install(this);
    ......
}

.....
}
           

使用 RefWatcher 監控那些本該被回收的對象:

public abstract class BaseFragment extends Fragment {

  @Override public void onDestroy() {
    super.onDestroy();
    RefWatcher refWatcher = ExampleApplication.getRefWatcher(getActivity());
    refWatcher.watch(this);
  }
}
           

最後如果有記憶體洩漏,會接收到相應的推送。

Android性能優化-記憶體洩漏(下) 如何進行記憶體洩漏的分析

這樣我們就能在編碼的階段,盡量的避免出現記憶體洩漏的情況。

如何對自己的項目進行記憶體洩漏分析

上面說了這麼多,怎麼來對我們自己的項目進行記憶體洩漏的分析呢?

一般我們都是在不知道項目中那裡有存在記憶體洩漏的情況下,怎麼來查找出那個地方出現了記憶體洩漏?

這裡我們主要檢查Activity及Fragment的記憶體洩漏情況。

使用Memory Usage檢視Activity及Fragment的記憶體洩漏情況,首先先運作自己項目到MainActivity,觀察 Menory Usage。

Android性能優化-記憶體洩漏(下) 如何進行記憶體洩漏的分析

待gc記憶體穩定後,我們可以執行一些操作,如進入其他的Activity執行其他操作,然後 檢測記憶體的抖動情況及gc穩定後,記憶體與初始記憶體的對比。

這裡我使用開啟不保留活動來模拟MainActivity的異常退出及恢複。繼續看Menory Usage。

Android性能優化-記憶體洩漏(下) 如何進行記憶體洩漏的分析

這個時候,我隻有在MainActivity出現過, 理論上應當隻有一個MainActivity的執行個體,這個地方就是一個值得懷疑的記憶體洩漏的點。這個時候我們就可以通過Mioniter和Mat進行記憶體分析

Android性能優化-記憶體洩漏(下) 如何進行記憶體洩漏的分析

這個時候我們可以看到引用的的可懷疑對象,接着我們就進入源碼分析。

Android性能優化-記憶體洩漏(下) 如何進行記憶體洩漏的分析

果然這裡有一個單例持有了MainActivity的使用。

分析記憶體洩漏是一個體力活,我們大概在項目中主要要記住。

  1. 使用leakcanary 在編碼階段進行檢測
  2. 結合記憶體抖動及Memory Usage 檢查Activity及Fragment的的洩漏情況
  3. 使用Monitor及Mat進行引用持有分析找出懷疑的對象
  4. 分析源代碼,找到元兇

轉自:http://www.jianshu.com/p/2c9fc4e871a4

繼續閱讀