現在、アプリで OutOfMemoryError が発生しています。MAT を使用してデバッグを試みましたが、いくつかのアクティビティでリークを見つけるのはまだ困難です。その後、よりシンプルで使いやすいと思われる LeakCanary を見つけましたが、Google でも Leak Canary の使用に関する初心者向けのステップ バイ ステップ ガイドを見つけることができませんでした。build.gradle の依存関係を通じて LeakCanary をインストールしましたが、これまでのところ次のようになりました。
例アプリケーション.java
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);
}
final class KeyedWeakReference extends WeakReference<Object> {
public final String key;
public final String name;
KeyedWeakReference(Object referent, String key, String name,
ReferenceQueue<Object> referenceQueue) {
super(checkNotNull(referent, "referent"), checkNotNull(referenceQueue, "referenceQueue"));
this.key = checkNotNull(key, "key");
this.name = checkNotNull(name, "name");
}
}
public void watch(Object watchedReference, String referenceName) {
checkNotNull(watchedReference, "watchReference");
checkNotNull(referenceName, "referenceName");
if(debuggerControl.isDebuggerAttached()) {
return;
}
final long watchStartNanoTime = System.nanoTime();
String key = UUID.randomUUID().toString();
retainedKeys.add(key);
final KeyedWeakReference reference =
new KeyedWeakReference(watchedReference, key, referenceName, queue);
watchExecutor.execute()
}
}
LeakCanaryにオブジェクトを監視してもらいたいアクティビティがあるとします
サンプルアクティビティ.java
public class SampleActivity extends Activity implements View.OnClickListener {
ImageView level001, level002;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.choose_level);
level001 = (ImageView) findViewById(R.id.level001);
level002 = (ImageView) findViewById(R.id.level002);
// Do all kinds of functions
// How do I use LeakCanary to watch these objects?
}
}
では、LeakCanary を使用して、どのオブジェクトがメモリ リークの原因になっているかを確認するにはどうすればよいでしょうか?
ベストアンサー1
リーク カナリアの優れた点は、その動作が自動化されていることです。デフォルトでは、適切に GC されていないアクティビティを「監視」しています。そのため、何もしなくても、アクティビティがリークしている場合は通知を受け取ることができます。
私のプロジェクトでは、次のような追加メソッドを追加しましたApplication
:
public class ExampleApplication extends Application {
public static ExampleApplication instance;
private RefWatcher refWatcher;
@Override
public void onCreate() {
super.onCreate();
instance = this;
refWatcher = LeakCanary.install(this);
}
public void mustDie(Object object) {
if (refWatcher != null) {
refWatcher.watch(object);
}
}
}
したがって、ガベージ コレクション、メモリ リーク、カナリアに関して重要なのは、いつ収集する必要があるかを把握し、その項目を監視するように要求することです。
たとえば、次のコードで「ベース フラグメント」を使用します。
@Override
public void onDestroy() {
super.onDestroy();
ExampleApplication.instance.mustDie(this);
}
この方法はLeakCanary
、フラグメントがメモリをリークしているかどうかをチェックしようとしています。
したがって、アプリでさらに実装するには、ガベージ コレクションする必要があることはわかっているが、実際には実行されない可能性があり、どこで実行されるかわからないタスクまたはインスタンスに対して、次のように呼び出すこともできます。ExampleApplication.instance.mustDie(object);
そして、アプリケーションを実行し、デバイスを回転させてリークを強制的に発生させる必要があります。そうすることで、リーク カナリアがスタック トレースを取得/分析し、修正方法に関する貴重な情報を提供できるようになります。
お役に立てれば幸いです。