其他分享
首页 > 其他分享> > Android LeakCanary的使用和原理,移动端app开发框架

Android LeakCanary的使用和原理,移动端app开发框架

作者:互联网

.reason(“Android AOSP sometimes keeps a reference to a destroyed activity as a”

最后调用了buildAndInstall方法,创建了一个RefWatcher对象并返回,这个对象是用于检测是否有对象未被回收导致的内存泄露

/**

因为分析泄露是在另一个进程进行的,所以判断当前启动的Application是否在分析内存泄露的进程中,如果是就直接返回DISABLED,不在进行后续初始化,如果发现是在程序主进程中,就进行初始化

LeakCanary.enableDisplayLeakActivity(context);主要作用是调用PackageManagerDisplayLeakActivity设置为可用。

public static void enableDisplayLeakActivity(Context context) {
setEnabled(context, DisplayLeakActivity.class, true);
}

public static void setEnabled(Context context, final Class<?> componentClass,
final boolean enabled) {
final Context appContext = context.getApplicationContext();
executeOnFileIoThread(new Runnable() {
@Override public void run() {
setEnabledBlocking(appContext, componentClass, enabled);
}
});
}

public static void setEnabledBlocking(Context appContext, Class<?> componentClass,
boolean enabled) {
ComponentName component = new ComponentName(appContext, componentClass);
PackageManager packageManager = appContext.getPackageManager();
int newState = enabled ? COMPONENT_ENABLED_STATE_ENABLED : COMPONENT_ENABLED_STATE_DISABLED;
// Blocks on IPC.
packageManager.setComponentEnabledSetting(component, newState, DONT_KILL_APP);
}

从配置文件看LeakCanary这几个文件都是运行在新进程的,DisplayLeakActivity默认enable=false,这样就可以一开始隐藏启动图标

接着 ActivityRefWatcher.install((Application) context, refWatcher);这里把refWatcher当做参数传入,同时对Activity的生命周期进行了监听

public static void install(Application application, RefWatcher refWatcher) {
new ActivityRefWatcher(application, refWatcher).watchActivities();
}

public void watchActivities() {
// Make sure you don’t get installed twice.
stopWatchingActivities();
application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
}

public void stopWatchingActivities() {
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks);
}

private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
new Application.ActivityLifecycleCallbacks() {
@Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}

@Override public void onActivityStarted(Activity activity) {
}

@Override public void onActivityResumed(Activity activity) {
}

@Override public void onActivityPaused(Activity activity) {
}

@Override public void onActivityStopped(Activity activity) {
}

@Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}

@Override public void onActivityDestroyed(Activity activity) {
ActivityRefWatcher.this.onActivityDestroyed(activity);
}
};

void onActivityDestroyed(Activity activity) {
refWatcher.watch(activity);
}

首先就是注册Activity的生命周期的监听器lifecycleCallbacks,这个监听器可以监听项目中所有Activity的的生命周期,然后在Activity销毁调用onActivityDestroyed的时候,LeakCanary就会获取这个Activity,然后对其进行分析,看是否有内存泄露

分析内存泄露

这里分析对象是否内存泄露的是RefWatcher类,下面简单介绍一下这个类的成员变量

从上面可以看出,每当Activity销毁,就会调用RefWatcherwatch方法,去分析是否是内存泄露

public void watch(Object watchedReference) {
watch(watchedReference, “”);
}

public void watch(Object watchedReference, String referenceName) {
if (this == DISABLED) {
return;
}
checkNotNull(watchedReference, “watchedReference”);
checkNotNull(referenceName, “referenceName”);
final long watchStartNanoTime = System.nanoTime();
String key = UUID.randomUUID().toString();
retainedKeys.add(key);
final KeyedWeakReference reference =
new KeyedWeakReference(watchedReference, key, referenceName, queue);

ensureGoneAsync(watchStartNanoTime, reference);
}

上面代码主要作用是,先生成一个随机数key放在retainedKeys容器里,用来区分对象是否被回收,创建了一个弱引用,然后把要分析的Activity对象存入,然后调用了ensureGoneAsync方法

private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
watchExecutor.execute(new Retryable() {
@Override public Retryable.Result run() {
return ensureGone(reference, watchStartNanoTime);
}
});
}

然后用watchExecutor去调度分析任务,这个主要是保证,在主线程进行,延迟5s,让系统有时间GC

@SuppressWarnings(“ReferenceEquality”) // Explicitly checking for named null.
Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
long gcStartNanoTime = System.nanoTime();
long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);

removeWeaklyReachableReferences();

if (debuggerControl.isDebuggerAttached()) {
// The debugger can create false leaks.
return RETRY;
}
if (gone(reference)) {
return DONE;
}
gcTrigger.runGc();
removeWeaklyReachableReferences();
if (!gone(reference)) {
long startDumpHeap = System.nanoTime();
long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);

File heapDumpFile = heapDumper.dumpHeap();
if (heapDumpFile == RETRY_LATER) {
// Could not dump the heap.
return RETRY;
}
long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
heapdumpListener.analyze(
new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
gcDurationMs, heapDumpDurationMs));
}
return DONE;
}

private void removeWeaklyReachableReferences() {
// WeakReferences are enqueued as soon as the object to which they point to becomes weakly
// reachable. This is before finalization or garbage collection has actually happened.
KeyedWeakReference ref;
while ((ref = (KeyedWeakReference) queue.poll()) != null) {
retainedKeys.remove(ref.key);
}
}

private boolean gone(KeyedWeakReference reference) {
return !retainedKeys.contains(reference.key);
}

首先通过removeWeaklyReachableReferences()方法,尝试从弱引用队列获取待分析对象,如果不为空说明被系统回收了,就把retainedKeys中的key值移除,如果被系统回收直接返回DONE,如果没有被系统回收,就手动调用 gcTrigger.runGc();手动触发系统gc,然后再次调用removeWeaklyReachableReferences()方法,如过还是为空,则判断为内存泄露

GcTrigger DEFAULT = new GcTrigger()
{
@Override public void runGc() {
// Code taken from AOSP FinalizationTest:
// https://android.googlesource.com/platform/libcore/+/master/support/src/test/java/libcore/
// java/lang/ref/FinalizationTester.java
// System.gc() does not garbage collect every time. Runtime.gc() is
// more likely to perfom a gc.
Runtime.getRuntime().gc();
enqueueReferences();
System.runFinalization();
}

private void enqueueReferences() {
// Hack. We don’t have a programmatic way to wait for the reference queue daemon to move
// references to the appropriate queues.
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new AssertionError();
}
}
};

手动触发GC后,调用enqueueReferences方法沉睡100ms,给系统GC时间, System.runFinalization();,这个是强制调用已失去引用对象的finalize方法

确定有内存泄漏后,调用heapDumper.dumpHeap();生成.hprof文件,然后回调到heapdumpListener监听,这个监听实现是ServiceHeapDumpListener类,会调analyze()方法

public final class ServiceHeapDumpListener implements HeapDump.Listener {

@Override public void analyze(HeapDump heapDump) {
checkNotNull(heapDump, “heapDump”);
HeapAnalyzerService.runAnalysis(context, heapDump, listenerServiceClass);
}
}

HeapDump是一个modle类,里面用于储存一些分析类强引用的需要信息 HeapAnalyzerService.runAnalysis方法是发送了一个intent,启动了HeapAnalyzerService服务,这是一个intentService

public static void runAnalysis(Context context, HeapDump heapDump,
Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
Intent intent = new Intent(context, HeapAnalyzerService.class);
intent.putExtra(LISTENER_CLASS_EXTRA, listenerServiceClass.getName());
intent.putExtra(HEAPDUMP_EXTRA, heapDump);
context.startService(intent);
}

启动服务后,会在onHandleIntent方法启动分析,找到内存泄露的引用关系

@Override
protected void onHandleIntent(Intent intent) {
if (intent == null) {
CanaryLog.d(“HeapAnalyzerService received a null intent, ignoring.”);
return;
}
String listenerClassName = intent.getStringExtra(LISTENER_CLASS_EXTRA);
HeapDump heapDump = (HeapDump) intent.getSerializableExtra(HEAPDUMP_EXTRA);

HeapAnalyzer heapAnalyzer = new HeapAnalyzer(heapDump.excludedRefs);

AnalysisResult result = heapAnalyzer.checkForLeak(heapDump.heapDumpFile, heapDump.referenceKey);
AbstractAnalysisResultService.sendResultToListener(this, listenerClassName, heapDump, result);
}

找到引用关系

public static void sendResultToListener(Context context, String listenerServiceClassName,
HeapDump heapDump, AnalysisResult result) {
Class<?> listenerServiceClass;
try {
listenerServiceClass = Class.forName(listenerServiceClassName);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
Intent intent = new Intent(context, listenerServiceClass);
intent.putExtra(HEAP_DUMP_EXTRA, heapDump);
intent.putExtra(RESULT_EXTRA, result);
context.startService(intent);
}

listenerServiceClassName就是开始LeakCanary.install方法传入的DisplayLeakService,它本身也是一个intentService

@Override
protected final void onHandleIntent(Intent intent) {
HeapDump heapDump = (HeapDump) intent.getSerializableExtra(HEAP_DUMP_EXTRA);
AnalysisResult result = (AnalysisResult) intent.getSerializableExtra(RESULT_EXTRA);
try {
onHeapAnalyzed(heapDump, result);
} finally {
//noinspection ResultOfMethodCallIgnored
heapDump.heapDumpFile.delete();
}
}

然后调用自身的onHeapAnalyzed方法

protected final void onHeapAnalyzed(HeapDump heapDump, AnalysisResult result) {
String leakInfo = LeakCanary.leakInfo(this, heapDump, result, true);
CanaryLog.d("%s", new Object[]{leakInfo});
boolean resultSaved = false;
boolean shouldSaveResult = result.leakFound || result.failure != null;
if(shouldSaveResult) {
heapDump = this.renameHeapdump(heapDump);
resultSaved = this.saveResult(heapDump, result);
}
mp, AnalysisResult result) {
String leakInfo = LeakCanary.leakInfo(this, heapDump, result, true);
CanaryLog.d("%s", new Object[]{leakInfo});
boolean resultSaved = false;
boolean shouldSaveResult = result.leakFound || result.failure != null;
if(shouldSaveResult) {
heapDump = this.renameHeapdump(heapDump);
resultSaved = this.saveResult(heapDump, result);
}

标签:LeakCanary,app,heapDump,void,new,intent,Android,public,result
来源: https://blog.csdn.net/m0_66145060/article/details/122715874