Leakcanary作用:
判断是否有内存泄漏;
-
定位并dump出调用栈;
利用haha库去输出dump信息的。
haha库相关信息:https://github.com/square/haha
-
以图形方式展示给开发者;
更多Leakcanary信息参考:https://github.com/square/leakcanary
今天我们主要谈一下他判断内存泄漏的方式,也就是上面的第一项。
说明:
利用
Android
中Application
的android.app.Application.ActivityLifecycleCallbacks
回调,跟踪Activity
的生命周期,在有android.app.Application.ActivityLifecycleCallbacks.onActivityDestroyed(Activity)
的回调时把Activity
对象添加到java.lang.ref.WeakReference
中。当添加的对象变为弱引用就会添加到
java.lang.ref.WeakReference.WeakReference(T, ReferenceQueue<? super T>)
的第二个参数,弱引用队列中。利用
WeakReference
的这一特性,在有onActivityDestroyed
回调时,通过Runtime.getRuntime().gc()
去通知系统gc,等待100ms,然后通过java.lang.System.runFinalization()
方法,强制调用已经没有被引用的对象的java.lang.Object.finalize()
方法。-
检查
WeakReference
的第二个参数ReferenceQueue
队列,取出要检查的Activity
。 判断是否在队列中:如果存在:当前对象已变成弱引用,内存可以成功释放,也就不会有内存泄漏的问题
-
如果不存在:说明当前对象目前还被其他对象保持持有关系(有其他对象指向要释放的对象),没有按预期释放当前对象,代表这个对象被泄漏了。这种情况积累下来,就会带来
OutOfMemoryError
。
Demo
package com.xinghui.java.weakreference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
/**
*
* @author xinghui
*
*/
public class WeakReferenceTest {
/**
* 用于看验证效果。
* true: 最后有不能回收的内存
* false: 内存全部回收
*/
private static final boolean CONFIG_LEAK = true;
/**
* 被保留的对象列表
*/
static Set<Object> retainedObject;
static ReferenceQueue<ClassA> queue = new ReferenceQueue<ClassA>();
public static void main(String[] args) {
retainedObject = new CopyOnWriteArraySet<Object>();
ClassA mClassA = new ClassA();
ClassB mClassB = new ClassB();
mClassB.mClassA = mClassA;
if (CONFIG_LEAK) {
ClassC.container = mClassB;
}
/**
* 当mClassA变成弱引用时,会添加到queue队列
* A WeakReference may be cleared and enqueued as soon as is known to be weakly-referenced.
*/
WeakReference<ClassA> re = new WeakReference<ClassA>(mClassA, queue);
retainedObject.add(re);
mClassA = null;
mClassB = null;
removeWeaklyReachableReferences("NONE");
/**
* 1、Java中的System.gc()和Android中的System.gc()是有区别的;
* @see 2、libcore.java.lang.ref.FinalizationTester.induceFinalization()
*
*/
// System.gc() does not garbage collect every time. Runtime.gc() is
// more likely to perfom a gc.
Runtime.getRuntime().gc();// 通知系统gc
try {
/*
* Hack. We don't have a programmatic way to wait for the reference queue
* daemon to move references to the appropriate queues.
*/
Thread.sleep(100);
} catch (InterruptedException e) {
throw new AssertionError();
}
System.runFinalization(); // 强制调用*已经没有被引用的对象*的finalize方法
removeWeaklyReachableReferences("runFinalization");
if (retainedObject.size() > 0) {
for (Object o : retainedObject) {
System.out.println("++++++++++ retained Object " + o);
}
} else {
System.out.println("------------NO retained Object");
}
}
private static void removeWeaklyReachableReferences(String TAG) {
Reference<? extends ClassA> ref;
System.out.println(TAG + " start ");
while ((ref = queue.poll()) != null) {
retainedObject.remove(ref);
System.out.println("removed " + ref + " after " + TAG);
}
}
static class ClassA {
}
static class ClassB {
ClassA mClassA;
}
static class ClassC {
static ClassB container;
}
}