return;
}
ActivityRefWatcheractivityRefWatcher=newActivityRefWatcher(application,refWatcher);
activityRefWatcher.watchActivities();
}
installOnIcsPlus()方法先判断当前SDK版本号,如果SDK版本号低于4.0则什么都不做就直接返回了,那也就是说LeakCanary库在Android4.0之前是没法直接使用的,若要在4.0之前使用就需要在基类BaseActivity的onDestroy()方法中调用RefWatcher的watch()方法来监控。
接着是创建了一个ActivityRefWatcher实例对象并调用该对象的watchActivities()方法,根据方法名字就知道是监控Activity的,跟进源码看一下该方法,源码如下:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicvoidwatchActivities(){
//Makesureyoudon'tgetinstalledtwice.
//开始监控Activity之前先尝试移除已经添加过的回调,确保只添加一次
stopWatchingActivities();
application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
}
publicvoidstopWatchingActivities(){
//移除Application中已经添加的回调接口
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks);
}
通过阅读watchActivities()方法发现原来LeakCanary是巧妙的利用了Android4.0之后的API,因为在4.0之后Google给Application添加了Activity的生命周期回调接口,如果我们注入了该回调接口,那么当Activity的声明周期发生变化的时候就会回调相关方法。
我们看一下注入的回调接口lifecycleCallbacks,源码如下:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
privatefinalApplication.ActivityLifecycleCallbackslifecycleCallbacks=
newApplication.ActivityLifecycleCallbacks(){
@Override
publicvoidonActivityCreated(Activityactivity,BundlesavedInstanceState){
}
@Override
publicvoidonActivityStarted(Activityactivity){
}
@Override
publicvoidonActivityResumed(Activityactivity){
}
@Override
publicvoidonActivityPaused(Activityactivity){
}
@Override
publicvoidonActivityStopped(Activityactivity){
}
@Override
publicvoidonActivitySaveInstanceState(Activityactivity,BundleoutState){
}
@Override
publicvoidonActivityDestroyed(Activityactivity){
//每当Activity销毁时系统都会回调该方法
ActivityRefWatcher.this.onActivityDestroyed(activity);
}
};
在lifecycleCallbacks()回调方法中仅仅在onActivityDestroyed()方法中回调了ActivityRefWatcher的onActivityDestroyed()方法并把要销毁的Activity传递进来,因此我们可以猜测当Activity被销毁的时候都会触发onActivityDestroyed()方法,LeakCanary就是通过监控传递进来的Activity通过判断它的应用关系来检测是否是发生了内存泄露。
到这里我们已经知道了LeakCanary检测Activity的时机,接下来看看LeakCanary是如何判断Activity存在内存泄露的。
onActivityDestroyed()方法就是检测Activity是否发生内存泄露的,其源码如下:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
voidonActivityDestroyed(Activityactivity){
refWatcher.watch(activity);
}
onActivityDestroyed()方法中辗转调用了refWatcher的watch()方法(该方法可以监控所有的Java对象),watch()方法又调用其重载方法,代码如下:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
/**
*WatchestheprovidedreferencesandchecksifitcanbeGCed.Thismethodisnonblocking,
*thecheckisdoneonthe{@linkWatchExecutor}this{@linkRefWatcher}hasbeenconstructed
*with.
*
*@paramreferenceNameAnlogicalidentifierforthewatchedobject.
*/
publicvoidwatch(ObjectwatchedReference,StringreferenceName){
if(this==DISABLED){
return;
}
checkNotNull(watchedReference,"watchedReference");
checkNotNull(referenceName,"referenceName");
finallongwatchStartNanoTime=System.nanoTime();
Stringkey=UUID.randomUUID().toString();
retainedKeys.add(key);
finalKeyedWeakReferencereference=
newKeyedWeakReference(watchedReference,key,referenceName,queue);
ensureGoneAsync(watchStartNanoTime,reference);
}
watch()方法中先是校验当前程序是否是DEBUG模式,如果是就直接返回否则对传递进来的参数进行非空校验,校验通过之后通过生成一个唯一的UUID并存储在retainKeys中,然后根据这个UUID初始化一个KeyedWeakReference实例对象reference,reference中保留了当前UUID和name,然后调用了ensureGoneAsync()方法,该方法源码如下:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
privatevoidensureGoneAsync(finallongwatchStartNanoTime,finalKeyedWeakReferencereference){
watchExecutor.execute(newRetryable(){
@Override
publicRetryable.Resultrun(){
returnensureGone(reference,watchStartNanoTime);
}
});
}
ensureGoneAsync()方法中调用了watchExecutor的execute()方法,经过分析watchExecutor是AndroidWatchExecutor的实例对象,也就是说最终执行的是AndroidWatchExecutor的execute()方法,我们进入该方法看看:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
@Override
publicvoidexecute(Retryableretryable){
//确保在主线程中执行
if(Looper.getMainLooper().getThread()==Thread.currentThread()){
waitForIdle(retryable,0);
}else{
postWaitForIdle(retryable,0);
}
}
在AndroidWatchExecutor的execute()方法中首先判断当前线程是不是主线程,如果是主线程就直接调用waitForIdle()方法,否则调用postWaitForIdle()方法切换到主线后再执行waitForIdle()方法。
由此可见execute()方法是保证操作在主线程中进行,我们进入waitForIdle()方法看一下,源码如下所示:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
voidwaitForIdle(finalRetryableretryable,finalintfailedAttempts){
//Thisneedstobecalledfromthemainthread.
//当前方法只能在主线程中调用
Looper.myQueue().addIdleHandler(newMessageQueue.IdleHandler(){
@Override
publicbooleanqueueIdle(){
postToBackgroundWithDelay(retryable,failedAttempts);
returnfalse;
}
});
}
waitForIdle()方法中通过调用Looper的myQueue()方法拿到当前主线程的消息队列MessageQueue对象,接着调用MessageQueue对象的addIdleHandler()方法给当前消息队列添加一个IdleHandler实例对象,IdleHandler是一个接口,该接口中定义的queueIdle()方法的返回值为boolean类型,当返回true表示继续保持IdleHandler实例对象否则移除该实例对象。
需要说明的是:
addIdleHandler()方法的目的是给当前消息队列添加一个回调接口,当当前消息队列中没有可执行的消息时就会回调该IdleHandler的queueIdle()方法,说白了就是等到主线程空闲的时候就会回调queueIdle()方法,queueIdle()方法返回了false表明该方法只被执行一次。
在queueIdle()方法中调用了postToBackgroundWithDelay()方法,我们跟进postToBackgroundWithDelay()方法中看一下,该方法源码如下:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
privatevoidpostToBackgroundWithDelay(finalRetryableretryable,finalintfailedAttempts){
longexponentialBackoffFactor=(long)Math.min(Math.pow(2,failedAttempts),maxBackoffFactor);
longdelayMillis=initialDelayMillis*exponentialBackoffFactor;
backgroundHandler.postDelayed(newRunnable(){
@Override
publicvoidrun(){
//切换到子线程中执行,retryable.run()方法
Retryable.Resultresult=retryable.run();
if(result==RETRY){
//如果retryable的run方法返回类型为RETRY,则循环以上流程
postWaitForIdle(retryable,failedAttempts+1);
}
}
},delayMillis);
}
postToBackgroundWithDelay()方法又切换到切换到子线程中执行Retryable的run()方法,如果run()方法返回值为RETRY就继续调用postWaitForIdle()方法循环以上流程否则本次调用结束,由于Retryable的run()方法中调用的是RefWatcher的ensureGone()方法,我们进入该方法看一下,其源码如下所示:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
Retryable.ResultensureGone(finalKeyedWeakReferencereference,finallongwatchStartNanoTime){
longgcStartNanoTime=System.nanoTime();
longwatchDurationMs=NANOSECONDS.toMillis(gcStartNanoTime-watchStartNanoTime);
//尝试移除
removeWeaklyReachableReferences();
if(debuggerControl.isDebuggerAttached()){
//Thedebuggercancreatefalseleaks.
returnRETRY;
}
//gone()方法检测是否包含当前reference
if(gone(reference)){
returnDONE;
}
//触发垃圾回收器进行回收操作
gcTrigger.runGc();
//再次尝试移除操作
removeWeaklyReachableReferences();
//若gone()方法返回false,表示有内存泄露
if(!
gone(reference)){
longstartDumpHeap=System.nanoTime();
longgcDurationMs=NANOSECONDS.toMillis(startDumpHeap-gcStartNanoTime);
//把堆内存相关信息映射成文件
FileheapDumpFile=heapDumper.dumpHeap();
if(heapDumpFile==RETRY_LATER){
//Couldnotdumptheheap.
returnRETRY;
}
longheapDumpDurationMs=NANOSECONDS.toMillis(System.nanoTime()-startDumpHeap);
//分析堆内存的映射文件,判断是否发生内存泄露
heapdumpListener.analyze(
newHeapDump(heapDumpFile,reference.key,reference.name,excl