android 內存泄露分析及調試(LeakCanary使用)

LeakCanary是一個傻瓜化並且可視化的內存泄露分析工具

爲什麼需要LeakCanary?
因爲它簡單,易於發現問題,人人可參與。

簡單:只需設置一段代碼即可,打開應用運行一下就能夠發現內存泄露。而MAT分析需要Heap Dump,獲取文件,手動分析等多個步驟。
易於發現問題:在手機端即可查看問題即引用關係,而MAT則需要你分析,找到Path To GC Roots等關係。
人人可參與:開發人員,測試測試,產品經理基本上只要會用App就有可能發現問題。而傳統的MAT方式,只有部分開發者纔有精力和能力實施。

什麼是內存泄露?

一些對象有着有限的生命週期。當這些對象所要做的事情完成了,我們希望他們會被回收掉。但是如果有一系列對這個對象的引用,那麼在我們期待這個對象生命週期結束的時候被收回的時候,它是不會被回收的。它還會佔用內存,這就造成了內存泄露。持續累加,內存很快被耗盡。(簡而言之,某個對象在該釋放的時候由於被其他對象持有沒有被釋放,因而造成了內存泄露。

比如,當 Activity.onDestroy 被調用之後,activity 以及它涉及到的 view 和相關的 bitmap 都應該被回收。但是,如果有一個後臺線程持有這個 activity 的引用,那麼 activity 對應的內存就不能被回收。這最終將會導致內存耗盡,然後因爲 OOM 而 crash。

常見內存泄露:

http://blog.csdn.net/gemmem/article/details/13017999

Android中使用Thread造成內存泄露的分析和解決

官網解釋:https://medium.com/square-corner-blog/leakcanary-detect-all-memory-leaks-875ff8360745

如何集成?
儘量在app下的build.gradle中加入以下依賴

testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
接下來,在你的應用裏寫一個自定義 Application ,並在其中“安裝” RefWatcher:
public class MyApplication extends Application {
    private static RefWatcher sRefWatcher;


    @Override
    public void onCreate() {
        super.onCreate();
        sRefWatcher = LeakCanary.install(this);
    }

    public static RefWatcher getRefWatcher() {
        return sRefWatcher;
    }
}

監控某個可能存在內存泄露的對象
MyApplication.getRefWatcher().watch(sLeaky);

哪些需要進行監控?

默認情況下,是對Activity進行了檢測。另一個需要監控的重要對象就是Fragment實例。因爲它和Activity實例一樣可能持有大量的視圖以及視圖需要的資源(比如Bitmap)即在Fragment onDestroy方法中加入如下實現

public class MainFragment extends Fragment {
    @Override
    public void onDestroy() {
        super.onDestroy();
        MyApplication.getRefWatcher().watch(this);
    }
}

何時進行監控?
首先,我們需要明確什麼是內存泄露,簡而言之,某個對象在該釋放的時候由於被其他對象持有沒有被釋放,因而造成了內存泄露。
因此,我們監控也需要設置在對象(很快)被釋放的時候,如Activity和Fragment的onDestroy方法。
一個錯誤示例,比如監控一個Activity,放在onCreate就會大錯特錯了,那麼你每次都會收到Activity的泄露通知。

如何解決?
常用的解決方法思路如下:
儘量使用Application的Context而不是Activity的;
使用弱引用或者軟引用;
手動設置null,解除引用關係;
將內部類設置爲static,不隱式持有外部的實例;
註冊與反註冊成對出現,在對象合適的生命週期進行反註冊操作;
如果沒有修改的權限,比如系統或者第三方SDK,可以使用反射進行解決持有關係;

如何使用LeakCanary?

http://www.jianshu.com/p/a8900eb3de12

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0511/2861.html

使用注意:

需要設置相應的文件存儲和查看權限;我所遇到的內存泄露問題,可參考:http://blog.csdn.net/jdsjlzx/article/details/51388847

ExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
        for (int i = 0; i < 10; i++) {
            final int pos = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    String threadName = Thread.currentThread().getName();
                    Log.e("TAG", "線程" + threadName + "任務" + pos);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

相關參考文章:

http://droidyue.com/blog/2016/03/28/android-leakcanary/

http://blog.csdn.net/clevergump/article/details/50995612

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