一:前言
最近看了看LeakCanary的源码,这里记录一下以防忘记,如有不足,恳请指出。
二:使用
LeakCanary的2.0版本使用特别简单,只需在项目build.gradle添加以下一句代码即可使用
dependencies {
// debugImplementation because LeakCanary should only run in debug builds.
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.6'
}
三:解析
1.初始化
很多人看了之后就有疑惑了,怎么不用初始化呢,这怎么可能就可以使用了。尤其是使用过LeakCanary1.0版本的看官肯定满肚子疑惑,请听我慢慢道来。我们打开源码,找到AppWatcherInstaller,打开源码如下
/**
* Content providers are loaded before the application class is created. [AppWatcherInstaller] is
* used to install [leakcanary.AppWatcher] on application start. 初始化类,在Manifest中注册了
*/
internal sealed class AppWatcherInstaller : ContentProvider() {
/**
* [MainProcess] automatically sets up the LeakCanary code that runs in the main app process.
*/
internal class MainProcess : AppWatcherInstaller()
/**
* When using the `leakcanary-android-process` artifact instead of `leakcanary-android`,
* [LeakCanaryProcess] automatically sets up the LeakCanary code
*/
internal class LeakCanaryProcess : AppWatcherInstaller()
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
AppWatcher.manualInstall(application)//真正初始化之处
return true
}
---省略
}
我们都知道ContentProvider是四大组件之一,必须注册。那她为什么能初始化金丝雀(即LeakCanary),它能保证Application不为空吗? 原理: ContentProvider的onCreate的调用时机介于Application的attachBaseContext和onCreate之间,Provider的onCreate优先于Application的onCreate执行,并且此时的Application已经创建成功,而Provider里的context正是Application的对象
注意点: 使用ContentProvider初始化的方式,我们需要注意一下几点: 首先,在Manifest里设置ContentProvider的时候要设置一个authorities,这个authorities相当于ContentProvider的标识,是不能重复的,为了保证不重复,我们再设置这个值的时候最好不要硬编码,而是使用以下的这种方式:使用appid+xxx
<provider
android:authorities="${applicationId}.xxprovider"
android:name=".MyLibRuntimeProvider"
android:exported="false"/>
由ActivityThread的handleBindApplication方法可以看到,是先调用installContentProviders方法,然后调用mInstrumentation.callApplicationOnCreate方法的。
2.原理
我们现在知道为什么不需要在Application初始化了,现在我们来理理金丝雀的工作原理。我们通过这个初始化的代码点进去AppWatcher
@JvmOverloads
fun manualInstall(
application: Application,
retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)
) {
checkMainThread()
check(!isInstalled) {
"AppWatcher already installed"
}
check(retainedDelayMillis >= 0) {
"retainedDelayMillis $retainedDelayMillis must be at least 0 ms"
}
this.retainedDelayMillis = retainedDelayMillis
if (application.isDebuggableBuild) {
LogcatSharkLog.install()
}
// Requires AppWatcher.objectWatcher to be set
LeakCanaryDelegate.loadLeakCanary(application)
watchersToInstall.forEach {
it.install()
}
}
/**
* Creates a new list of default app [InstallableWatcher], created with the passed in
* [reachabilityWatcher] (which defaults to [objectWatcher]). Once installed,
* these watchers will pass in to [reachabilityWatcher] objects that they expect to become
* weakly reachable.
*
* The passed in [reachabilityWatcher] should probably delegate to [objectWatcher] but can
* be used to filter out specific instances.初始化各种监听器比如activity、fragment等
*/
fun appDefaultWatchers(
application: Application,
reachabilityWatcher: ReachabilityWatcher = objectWatcher
): List<InstallableWatcher> {
return listOf(
ActivityWatcher(application, reachabilityWatcher),
FragmentAndViewModelWatcher(application, reachabilityWatcher),
RootViewWatcher(reachabilityWatcher),
ServiceWatcher(reachabilityWatcher)
)
}
/**
* The [ObjectWatcher] used by AppWatcher to detect retained objects.
* Only set when [isInstalled] is true.
*/
val objectWatcher = ObjectWatcher(
clock = { SystemClock.uptimeMillis() },
checkRetainedExecutor = {
check(isInstalled) {
"AppWatcher not installed"
}
mainHandler.postDelayed(it, retainedDelayMillis)//特定时间轮询一次
},
isEnabled = { true }
)
通过代码我们可以看到,里面都有一个objectWatcher,那这个objectWatcher是何方神圣呢。其实它是所有监听器的处理基类,其他的监听器都是通过监听页面生命周期来调用objectWatcher最终处理,比如ActivityWatcher
class ActivityWatcher(
private val application: Application,
private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityDestroyed(activity: Activity) {
reachabilityWatcher.expectWeaklyReachable(
activity, "${activity::class.java.name} received Activity#onDestroy() callback"
)
}
}
override fun install() {
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
override fun uninstall() {
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
}
}
那么我们再来看看ObjectWatcher是怎么处理的,主要代码如下:
class ObjectWatcher constructor(
private val clock: Clock,
private val checkRetainedExecutor: Executor,
/**
* Calls to [watch] will be ignored when [isEnabled] returns false
*/
private val isEnabled: () -> Boolean = { true }
) : ReachabilityWatcher {
private val onObjectRetainedListeners = mutableSetOf<OnObjectRetainedListener>()
/**
* References passed to [watch].
*/
private val watchedObjects = mutableMapOf<String, KeyedWeakReference>()//通过map集合来实现当前有几个泄露对象
private val queue = ReferenceQueue<Any>() //主要实现原理,通过弱引用对象队列查找
@Synchronized override fun expectWeaklyReachable(
watchedObject: Any,
description: String
) {
if (!isEnabled()) {
return
}
removeWeaklyReachableObjects()
val key = UUID.randomUUID()
.toString()
val watchUptimeMillis = clock.uptimeMillis()
val reference =
KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)//创建弱引用对象
SharkLog.d {
"Watching " +
(if (watchedObject is Class<*>) watchedObject.toString() else "instance of ${watchedObject.javaClass.name}") +
(if (description.isNotEmpty()) " ($description)" else "") +
" with key $key"
}
watchedObjects[key] = reference//添加key value值
checkRetainedExecutor.execute {//通过mainHandler.postDelayed()实现轮询查找队列里面的对象是否是弱引用,是则去除,否则内存泄露,通知用户
moveToRetained(key)
}
}
@Synchronized private fun moveToRetained(key: String) {
removeWeaklyReachableObjects()
val retainedRef = watchedObjects[key]
if (retainedRef != null) {
retainedRef.retainedUptimeMillis = clock.uptimeMillis()
onObjectRetainedListeners.forEach { it.onObjectRetained() }
}
}
private fun removeWeaklyReachableObjects() {
// 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.
var ref: KeyedWeakReference?
do {
ref = queue.poll() as KeyedWeakReference?//查找是否是弱引用之处
if (ref != null) {
watchedObjects.remove(ref.key)
}
} while (ref != null)
}
总结
一顿分析猛如虎,一看工资两百五。最后总结一下原理:
- 首先通过ContentProvider 初始化金丝雀
- 然后初始化各种监听器
- 通过监听页面销毁或者主动把对象加入监听,把对象加入到弱引用队列里面
- 通过定时轮询和queue.poll()方法查找对象是否是弱引用,如果过了某个时间,对象还是没有变为弱引用,则报泄露,否则移除队列
还有分析内存泄漏原因等原理后面看了再写