LeakCanaryでAndroidメモリの漏洩を確認

8993 ワード

LeakCanaryでAndroidメモリの漏洩を確認
文字数1769
読書2762
コメント6
好きです
前言
あなたは確率的なOOMに悩まされていますか?时には、OOMは幽霊のように、振り回すことができなくて、本当にそれをつかみたい时、また捕まえることができません.もしかすると、LeakCanaryで診断する時かもしれません.Androidの下でメモリの漏洩をチェックするためのオープンソースライブラリです.この記事では、主にその使い方、アーキテクチャ、その背後にある実装原理を紹介します.
Squareはこのライブラリを開発した理由を紹介した文章がある.彼らの1つの支払いの流れの中で、ユーザーの署名を使う必要があります.彼らは直接Bitmapで署名を描きます.Bitmapの大きさと画面の解像度は同じです.問題は、このBitmapオブジェクトを作成しようとすると、確率的なOOMが幽霊のように付随することです.彼らはいくつかの方法を試しました.
  • Bitmap.Config.ALPHA_8を使用してメモリ
  • を節約する.
  • OutOfMemoryError異常をキャプチャし、gcを呼び出してメモリをクリーンアップし、
  • を数回再試行する.
    結局これらは役に立たない.最終的に彼らは間違った方向に遠すぎることに気づいた.メモリリークが存在する場合、使用可能なメモリはますます少なくなります.この場合、OOMは特にBitmapのような大きなメモリオブジェクトを作成しようとする場合に発生します.
    前回の記事「Androidメモリとパフォーマンス」では、MATを使用してメモリの漏洩を分析する方法を紹介しました.要約すると、コアステップは次のとおりです.
  • OOMが発生するか、メモリリークの可能性のあるいくつかの操作を行った後、HPROFファイル
  • をエクスポートします.
  • はMAT結合コード分析を利用して、どのオブジェクトが回収されるべきか、システムスタックの中にあるかなどの参照異常を発見し、メモリ漏洩
  • である.
    これらのことを自動的に完了するツールがあれば、OOMが発生する前にメモリの漏洩を報告することができます.それはどんなに素晴らしいことでしょう.LeakCanaryはこのことをするために使われています.あなたのAppをテストするとき、メモリ漏れが発生した場合、ステータスバーに通知が表示されます.ロゴcatにも対応するロゴが通知されます.
    !!! notesの「啓発」LeakCanaryの背後にはいくつかの興味深い啓発がある.一つはSquareのような会社がOOMという問題に悩まされることです.二つ目は彼らも間違いを犯して、いくつかの方法を試しても役に立たないことです.3つ目は、彼らが最終的に優雅な方法でこの問題を解決し、オープンソースライブラリを通じてすべての人に仕事の成果を共有させることです.
    使用法
    Activity漏洩の監視
    ActivityはContextオブジェクトとしてよく用いられ,場合によっては様々なオブジェクトがActivityを参照する.したがって、Activity漏洩は重要なメモリ漏洩の1つです.
    public class ExampleApplication extends Application {
    
        public static RefWatcher getRefWatcher(Context context) {
            ExampleApplication application = (ExampleApplication) context.getApplicationContext();
            return application.refWatcher;
        }
    
        private RefWatcher refWatcher;
    
        @Override public void onCreate() {
            super.onCreate();
            refWatcher = LeakCanary.install(this);
        }
    }
    LeakCanary.install()は、構成されたRefWatcherのインスタンスを返す.Activityの漏洩を監視するために ActivityRefWatcherが同時に取り付けられています.つまり、Activity.onDestroy()が呼び出された後、このActivityが破棄されなかった場合、logcatはメモリ漏洩が発生したことを示すメッセージを印刷します.
        * com.example.leakcanary.MainActivity has leaked:
        * GC ROOT thread java.lang.Thread.<Java Local> (named 'AsyncTask #1')
        * references com.example.leakcanary.MainActivity$2.this$0 (anonymous class extends android.os.AsyncTask)     * leaks com.example.leakcanary.MainActivity instance
        * Reference Key: c4d32914-618d-4caf-993b-4b835c255873
        * Device: Genymotion generic Google Galaxy Nexus - 4.2.2 - API 17 - 720x1280 vbox86p
        * Android Version: 4.2.2 API: 17
        * Durations: watch=5100ms, gc=104ms, heap dump=82ms, analysis=3008ms

    !!! notes LeakCanary自動検出ActivityリークはAndroid ICS以上のバージョンのみサポートされています.Application.registerActivityLifecycleCallbacks()はAPI 14に導入されているからである.ICSの前にActivity漏洩を監視する場合は、Activity.onDestroy()メソッドを再ロードし、このメソッドでRefWatcher.watch(this)を呼び出して実装することができる.
    Fragment漏洩の監視
    public abstract class BaseFragment extends Fragment {
    
        @Override 
        public void onDestroy() {
            super.onDestroy();
            RefWatcher refWatcher = ExampleApplication.getRefWatcher(getActivity());
            refWatcher.watch(this);
        }
    }
    Fragment.onDestroy()が呼び出されると、このfragmentインスタンスが破棄されない場合、logcatから対応する漏洩情報が表示される.
    その他の漏洩の監視
        ...
        RefWatcher refWatcher = ExampleApplication.getRefWatcher(getActivity());
        refWatcher.watch(someObjNeedGced);
    someObjNeedGcedがメモリに残っている場合、logcatにメモリ漏洩のヒントが表示されます.
    LeakCanaryライブラリの統合
    dependencies {
        debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'
        releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'
    }

    Debugバージョンでは、LeakCanaryライブラリを統合し、メモリ漏洩モニタリングを実行しますが、releaseバージョンでは、操作のないwrapperを統合することで、プログラムのパフォーマンスに影響を与えません.
    げんり
    LeakCanaryフローチャート
    leakcanary
    LeakCanaryのメカニズムは次のとおりです.
  • RefWatcher.watch()は、オブジェクトを監視するためにKeyedWeakReferenceの弱い参照オブジェクト
  • を作成する.
  • AndroidWatchExecutorのバックグラウンドスレッドで弱参照がクリアされていることを確認し、クリアされていない場合はGC
  • を1回実行する.
  • 弱い参照オブジェクトがクリアされていない場合、メモリが漏洩していることを示すhprofファイルがエクスポートされ、appのファイルシステムディレクトリの下に
  • 保存される.
  • HeapAnalyzerServiceは、hprofファイルを分析するためにHeapAnalyzerを使用する個別のプロセスを開始する.別のオープンソースHAHAHAを使用します.
  • HeapAnalyzerは、KeyedWeakReferenceの弱い参照オブジェクトを検索することによって、内部漏洩
  • を検索する.
  • HeapAnalyzerは、メモリリークを解析し、オブジェクト参照チェーンを構築するために、KeyedWeakReferenceによって参照されるオブジェクトの最短の強い参照経路を計算する.
  • メモリ漏洩情報は、appプロセスで実行されるサービスであるDisplayLeakServiceに返される.次に、デバイス通知バーにメモリ漏洩情報を表示します.

  • いくつかの興味深いコード
    hprofファイルのエクスポート方法
    File heapDumpFile = new File("heapdump.hprof");
    Debug.dumpHprofData(heapDumpFile.getAbsolutePath());

    Android HeapDumperを参照できます.JAvaのコード.
    hprofファイルの分析方法
    これは比較的大きな話題で、興味のあるのは別のオープンソースHAHAHAに移動することができて、その祖先はMATです.
    HandlerThreadの使用方法
    AndroidWatchExecutorを参照してください.JAvaのコード、特にHandler、Loopの使用について.
    どのようにある変数がGCで回収されたことを知っていますか?
    RefWatcherを参照してください.JAvaのensureGone()関数.最も主にWeakReferenceおよびReferenceQueue機構を利用する.簡単に言えば、弱引用WeakReferenceで引用されたオブジェクトが回収されると、このWeakReferenceオブジェクトが ReferenceQueueキューに追加され、そのpoll()方法でこの回収されたオブジェクトのWeakReference例を取得することができ、さらに監視が必要な対象が回収されたかどうかを知ることができる.
    メモリリークについて
    メモリの漏洩は、Cursorが閉じていないなど、容易に発見できる可能性があります.例えばActivity.onResume()でregisterは傍受が必要な事件をリスニングしたが、Activity.onPause()でunregisterを忘れた.メモリ漏洩は、LeakCanaryのサンプルコードなど、暗黙的に参照され、画面を回転させるときにのみ発生する可能性があります.さらに、Android SDK自体のBUGによるメモリ漏洩など、無力なメモリ漏洩も発見しにくい.AndroidExcludedRefs.JAvaには、既知のAOSPバージョンとそのOEM実装バージョンに存在するメモリ漏洩が記録されています.
    今期の推奨
    プロットツールplanUMLをお勧めします.その最大の特徴は、スクリプトを使用して図面を描くことです.starUMLとの最大の違いは、前者がマイクロソフトのvisioに似たグラフィックツールであり、スクリプトグラフィックをサポートし、後者がモデリングツールであることです.planUMLの公式ドキュメントです.また、Sublime Textなどの拡張もサポートされています.本稿のフローチャートはplanUMLで描かれています.