**
原理:watch(监视)一个即将要销毁的对象
**
为什么产生内存泄露?
1.当一个对象已经不需要再使用了,有一个正在使用的对象持有了这个对象的引用
2.有些对象只有有限的生命周期
内存泄漏会导致什么问题?
1.OOM
3.内存泄漏的场景
单例导致内存泄漏
非静态内部类创建静态实例 (非静态内部类会持有外部内的引用)
内部类虽然和外部类写在同一个文件中, 但是编译完成后, 还是生成各自的class文件,内部类通过this访问外部类的成员。1 编译器自动为内部类添加一个成员变量, 这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象(this)的引用;2 编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型, 在构造方法内部使用这个参数为内部类中添加的成员变量赋值;3在调用内部类的构造函数初始化内部类对象时,会默认传入外部类的引用。
handler造成内存泄漏
Message消息没有执行完,Activity关闭的时候无法被回收就会导致内存泄漏
解决方法:1.将Handler定义类静态内部类;2.将Activity变成弱引用
线程造成内存泄漏
和handler是一样的,解决方法是将AsyncTask和Runable定义为static,因为static是不会持有内部类的引用的
WebView造成内存泄漏
解决方式:1.放在单独的进程 2.在当前Webview的Activity的onDestory方法里面主动kill当前进程
LeakCanary原理
工作机制
RefWatcher.watch()创建一个KeyedWeakReference到要被监控的对象。
然后在后台线程检查引用是否被清除,如果没有,调用GC。
如果引用还是未被清除,把heap内存dump到APP对应的文件系统中的一个.hprof文件中。
在另一个进程中的HeapAnalyzerService有一个HeapAnalyzer使用HAHA解析这个文件。
在Heap Dump中,HeapAnalyzer根据唯一的reference key找到了KeyedWeakReference,并定位了泄漏的引用。
HeapAnalyzer计算到GC Roots的最短强引用路径,并确定是否泄漏,如果是的话,建立导致泄漏的引用链。
引用链传递到APP进程中的DisplayLeakService,并以通知的形式展示出来
/**
* LeakCanary.java
*/
public static @NonNull RefWatcher install(@NonNull Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
.buildAndInstall();
}
/**
* RefWatcher.java
*/
public @NonNull RefWatcher buildAndInstall() {
if (LeakCanaryInternals.installedRefWatcher != null) {
throw new UnsupportedOperationException("buildAndInstall() should only be called once.");
}
RefWatcher refWatcher = build();
if (refWatcher != DISABLED) {
if (enableDisplayLeakActivity) {
LeakCanaryInternals.setEnabledAsync(context, DisplayLeakActivity.class, true);
}
if (watchActivities) {
ActivityRefWatcher.install(context, refWatcher);
}
if (watchFragments) {
FragmentRefWatcher.Helper.install(context, refWatcher);
}
}
LeakCanaryInternals.installedRefWatcher = refWatcher;
return refWatcher;
}
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);
}
private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
watchExecutor.execute(new Retryable() {
@Override public Retryable.Result run() {
return ensureGone(reference, watchStartNanoTime);
}
});
}
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);
HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key)
.referenceName(reference.name)
.watchDurationMs(watchDurationMs)
.gcDurationMs(gcDurationMs)
.heapDumpDurationMs(heapDumpDurationMs)
.build();
heapdumpListener.analyze(heapDump);
}
return DONE;
}
/**
* ActivityRefWatcher.java
*/
public static void install(@NonNull Context context, @NonNull RefWatcher refWatcher) {
Application application = (Application) context.getApplicationContext();
ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);
application.registerActivityLifecycleCallbacks(activityRefWatcher.lifecycleCallbacks);
}
private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
new ActivityLifecycleCallbacksAdapter() {
@Override public void onActivityDestroyed(Activity activity) {
refWatcher.watch(activity);
}
};