Diary

Diary

日々学んだことをアウトプットする場として初めてみました

android でメモリーリークを調べてみた

モリーリークとは

Java のランタイムの文脈においてメモリーリークとは、ガベージコレクション (GC) と強く関連しています。具体的には、必要無くなったオブジェクトの参照を持ち続け、GC が削除をいつまでも行わないことを指します。

すぐにバグを引き起こすわけではありませんが、リソースが限られている Android においては OOM (out of memory) crash を引き起こす可能性があります。

また、GC を挙動を知る必要もあるため、リークを検知するのも防ぐのも簡単ではありません。

[目次]

環境

- gradle:7.0.4
- kotlin-gradle-plugin:1.5.21
- targetSdk 31
- leakcanary-android:2.8.1'

android で検知する

android で簡単にメモリーリークを調べるには、LeakCanaryというライブラリを使用します。

依存関係を追加する

dependencies {
    ...
    // to detect memory leak
    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
}

使い方

上で依存関係を導入したら、あとはアプリを debug モードでビルドするだけです。

ビルドが完了すると、作成中ののアプリとは別アプリとして、以下のアイコンのアプリがインストールされています。

f:id:kokoichi206:20220204000703p:plain

このアプリを開いてみると以下のような画面が表示されます。

f:id:kokoichi206:20220204002615p:plain

このままだと面白くないので、意図的にメモリーリークを発生させてみます。

モリーリーク発生時

モリーリークが検知されると、アプリ内に以下のような通知が出ます。

f:id:kokoichi206:20220204002823p:plain

より詳細ページを見てみます。

f:id:kokoichi206:20220204003004p:plain

f:id:kokoichi206:20220204003231p:plain

どこで発生したかや、どのくらいの量のメモリーリークが発生しているか、その詳細が記載されています。

使用できない!(インストールできない)

debug モードでビルドするだけなのですが、自分の場合は Logcat に以下のようなメッセージがでて使用できませんでした。

D/LeakCanary: LeakCanary is currently disabled: test class org.junit.Test was found in classpath.
D/LeakCanary: Setting up flushing for Thread[LeakCanary-Heap-Dump,5,main]

そこで、こちらのドキュメントに従い次の1文をres/values/strings.xmlに追加することで解決しました。

<resources>
    ...
    <!-- to detect memory leak -->
    <string name="leak_canary_test_class_name">assertk.Assert</string>
</resources>

この時は Logcat のメッセージが以下のようになっていて、検知する準備が整っていることがわかります。

D/LeakCanary: LeakCanary is running and ready to detect memory leaks.
D/LeakCanary: Setting up flushing for Thread[LeakCanary-Heap-Dump,5,main]

おわりに

ドキュメントにはリソースファイルをどこに追加するかが書かれてなかったので少し戸惑いましたが、今作ってるアプリにメモリーリークがなくてよかったです。

定期的に確認していきたいと思います(もしくは自動で確認するフローを作りたいです)