An Introduction to memory management and memory leaks on Android

このツールは疑わしいリークへの参照を見つけるには非常に便利ですが、未知のリークを見つけるにはかなり難しく複雑で、かなりの量の分析が必要なことを覚えておくとよいでしょう。 とはいえ、もし使いこなせたら、素晴らしいツールです!

LeakCanary

Image from LeakCanary

メモリ リークの検出のもうひとつの方法として Leak Canary を使用することが挙げられます。 これは、破壊されたオブジェクトへの弱い参照をヒープに保持する ObjectWatcher クラスを使用することで動作します。 もしその参照が5秒以内に消去されず、ガベージコレクタが実行された場合、そのオブジェクトは保持されているとみなされ、logcatにメモリリークの可能性として記録されます。 かなり賢いですね。

始めるには、単に依存関係の中にあるライブラリを build.gradle ファイルに追加し、同期してコンパイルします。

Add the LeakCanary library

As soon as the start the application, you can see the LeakCanary output in the logcat as watching instants and retains object.If the LeakCanaryは、アプリケーションが起動すると、インスタントとオブジェクトが保持されていることを確認できます。 リークを誘発するために、私は TaskManager アプリでいくつかの新しいタスクを追加しました。 ほどなくして、LeakCanary からリークの可能性を示すこの通知が届きました!

通知をクリックするだけで、「ヒープのダンプ」してリークの可能性について調査すると、アプリに次のダイアログが表示されます。

LeakCanary はリークを調査中 …

Leak Canary は次に保持オブジェクトの位置を通してヒープを分析し、保持オブジェクトそれぞれへの参照のパスとなるリーク トレースを発見します。 いったん完了すると、保持されたオブジェクトとリークの数を要約した通知が表示されます。

どうやらリークが見つかったようです!。 それをクリックすると、完全なリークトレースが表示されます:

TaskActivity がリークしていると伝えています。下線で示した参照は、mContext から SingletonExample でリークが発生しています – 聞き覚えがありませんか。 これで、LeakCanary を使ってリークを見つける方法がわかりました。 😃

Avoiding memory leaks

さて、メモリ リークを発見したところで、今後どのようにしてリークを回避すればよいでしょうか。 以下に、最も一般的な原因とパターンをいくつか紹介します。

Photo by Bogomil Mihaylov on Unsplash

Broadcast receivers

Broadcast receivers はシステム全体のブロードキャスト イベントまたはインテントを聞くために使用でき、これらはロー バッテリーなどのデバイス情報を表示します。 日付や接続の変更(機内モードがオフにされたなど)。 それらを使用する場合、ブロードキャスト受信機の登録を解除することを覚えておく必要があります。そうしないと、どうしても活動への参照を保持することになります。それを回避する方法。

回避方法: アクティビティ内の onStop() でブロードキャスト レシーバーに対して unregister() を呼び出すだけです。このパターンは asyncTask、TimerTask およびスレッドにも見られ、リークを避けるために onDestroy() でキャンセルする必要がある。

Context to Singleton class

時にはアクティビティから Singleton クラスにコンテキストを渡すことが必要な場合があります。 この例としては、リソース、サービス、または内部ファイルにアクセスする必要があるユーティリティ クラスが挙げられます。 しかし、コンテキストを渡すことは、必然的にアクティビティへの参照を保持することを意味します。 アクティビティから this を渡す代わりに、利用可能な場合はアプリケーション コンテキストを渡すことができます (いつどのコンテキストを使用するかについて詳しく知りたい場合は、この記事が本当に役に立ちました!)。

静的参照

静的としてビューまたはアクティビティを参照することは、そのアクティビティへの参照がガベージ コレクションされないことを意味します。 これは、常に避けるべきです。

それを避けるにはどうしたらよいでしょうか。 何らかの理由でそれを行う必要がある場合、onDestroy().

でそれをヌルに設定することにより、確実に破棄できます。

内部クラス参照

内部クラスは、外部クラスへの暗黙の参照を保持することにより、しばしばリークを引き起こします。 これは、クラス変数が静的として宣言されている場合、またはクラス自体が静的として宣言されていない場合に起こります。 混乱しますか? しかし、以下の簡単なルールに従えば、簡単に回避することができます。 外部クラスへの参照を保持しないように内部クラスを static にし、内部クラスの static 変数を決して作成しない。 匿名クラスも同様です。

以上です。 メモリリークとそれを回避する方法について、いくつか学んでいただけたでしょうか。 ハッピーコーディング! 😄

Here are a number of articles and documentation I found particularly useful when learning about memory leaks:

メモリリークについて学ぶとき、特に役に立ちました。

コメントを残す

メールアドレスが公開されることはありません。