これはおそらく愚かな質問であることは知っていますが、Androidの開発はかなり新しく、現在、アプリでOutOfMemoryErrorが発生しています。その後、LeakCanaryを見つけました。これはよりシンプルで使いやすいようですが、GoogleでもLeak Canaryの使用に関する初心者向けのステップガイドは見つかりませんでした。 build.gradleの依存関係を介してLeakCanaryをインストールしましたが、これがこれまでに得たものです。
ExampleApplication.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にオブジェクトを監視させたいアクティビティがあるとします
SampleActivity.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 function
// How do I use LeakCanary to watch these objects ?
}
}
LeakCanaryを使用して、メモリリークの原因となっているオブジェクトを確認するにはどうすればよいですか。ご協力いただきありがとうございます。
リークカナリアの良いところは、自動化の仕組みです。デフォルトでは、適切に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);
そして、アプリケーションを実行してデバイスを回転させ、リークを強制的に発生させる必要があります。リークカナリアはスタックトレースを取得/分析し、修正方法に関する貴重な情報を提供できます。
役に立てば幸いです。
LeakCanaryの使用方法についても同じ質問がありました。起動方法の基本的な例と、リークされたオブジェクトへの最初のパスを確認したかっただけです。
LeakCanaryの動作方法の基本的な例を次に示します。
LeakCanaryの使用方法(4分13秒)
克服しなければならなかった問題の1つは、デバッグモードではなく通常の実行モードでアプリを起動する必要があることを理解することでした。また、基本的な手順から逸脱して、アプリケーションレベルの_build.gradle
_ファイルを次のように設定する必要がありました。
_dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-Android:1.5.4'
releaseImplementation 'com.squareup.leakcanary:leakcanary-Android:1.5.4'
}
_
LeakCanaryはデバッグ時にリーク検出を無視する であるため、debugImplementation
は機能しませんでした。 LeakCanaryは、リリース用にライブラリの "no-op"バージョン を提供すると言いますが、デバッグが機能しなかったため、上記のreleaseImplementation
を推奨_com.squareup.leakcanary:leakcanary-Android-no-op:1.5.4
_から_com.squareup.leakcanary:leakcanary-Android:1.5.4
_。
ビデオでわかるように、対処しなければならなかったもう1つの問題は、LeakCanaryへの書き込みアクセス権の付与でした。下にスワイプすると、LeakCanaryから、書き込みアクセスの取得に失敗したという通知が表示されました( 詳細 )。許可のリクエストを見たことがありません。そのため、あるケースでは(ビデオには表示されていません)、設定アプリにアクセスし、アプリを見つけて(LeakCanaryがインストールする「リーク」というアプリとは対照的に)書き込みアクセスを許可します。ビデオでは、通知に応答することで許可を与えたため、その必要はありませんでした。次に、アプリを使用している間、新しい通知を定期的に確認します(下にスワイプします)。 「XYZActivity leaked 217 KB」などのメッセージが表示されました。私はそれをタップし、それがそのリークアプリに私を連れて行った。
また、 分析が完了し、携帯電話でメモリリーク通知が表示されるまでに数分かかることがあります 。
メモリリークの一部を修正したので、LeakCanaryを使用して修正を確認します。ただし、LeakCanaryが何も報告しない場合、それは必ずしも私のリークが修正されたためだとは思わない。 LeakCanaryが壊れている可能性があります。
LeakCanaryを使用してメモリリークの修正を確認する方法(16分34秒)
LeakCanaryでメモリリークを検証するプロセス:1. LeakCanaryを使用してメモリリークが存在することを確認します2.メモリリークを修正し、LeakCanaryがリークなしを報告することを確認します3。
LeakCanaryが動作しているとき、ステータス情報はほとんど表示されないため、何もしていないかどうかを知るのは困難です。これにより、実際には修正していなかったのに、メモリリークを修正したと思うようになりました。上記の3つの手順は、LeakCanaryを使用してメモリリークの修正を確認するための最良の方法です。
ここでアプリケーションで使用しました
import Android.content.Context;
import Android.support.multidex.MultiDex;
import Android.support.multidex.MultiDexApplication;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;
import school.my.com.school.BuildConfig;
public class AppController extends MultiDexApplication {
private RefWatcher refWatcher;
public static RefWatcher getRefWatcher(Context context) {
AppController application = (AppController) context.getApplicationContext();
return application.refWatcher;
}
@Override
public void onCreate() {
super.onCreate();
if(BuildConfig.DEBUG)
refWatcher = LeakCanary.install(this);
}
}
MultiDexApplicationの代わりにこちらのアプリケーションを使用できます
私は以下のようなリークカナリアを使用しました:
1)Gradle依存関係:
debugImplementation 'com.squareup.leakcanary:leakcanary-Android:1.4'
2)アプリケーションクラス:
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectCustomSlowCalls()
.detectNetwork()
.penaltyLog()
.penaltyDeath()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectActivityLeaks()
.detectLeakedClosableObjects()
.detectLeakedRegistrationObjects()
.detectLeakedSqlLiteObjects()
.penaltyLog()
.penaltyDeath()
.build());
LeakLoggerService.setupLeakCanary(this);
}
}
3)LeakLoggerServiceクラス:このクラスをgradleによって作成されたデバッグパッケージに配置します。
public class LeakLoggerService extends DisplayLeakService {
public static void setupLeakCanary(Application application) {
if (LeakCanary.isInAnalyzerProcess(application)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(application, LeakLoggerService.class,
AndroidExcludedRefs.createAppDefaults().build());
}
@Override
protected void afterDefaultHandling(HeapDump heapDump, AnalysisResult result, String leakInfo) {
if (!result.leakFound || result.excludedLeak) {
return;
}
Log.w("LeakCanary", leakInfo);
}
4)サービスをマニフェストファイルに登録し、1つの権限を付与します。
<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE"/>
<service Android:name=".LeakLoggerService" />
5)最後に、セットアップが成功したかどうかを確認します:アクティビティをリークします;)
public class Main2Activity extends AppCompatActivity {
static TextView label;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
label = new TextView(this);
label.setText("asds");
setContentView(label);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
}
}
このアクティビティを強制終了し、タグでログを確認します:LeakCanary
うまくいくはず...