前言
LeakCanary是Square公司为Android开发者提供的一个自动检测内存泄漏的工具,在4月23日推出了2.0预览版,更新内容见Github,其中新增了一个LeakSentry库,该库作为LeakCanary的开关,可以实时查看那些被观察的对象是否可能内存泄露,并且可以独立引入使用,下面从源码角度来分析下该库。
源码分析
首先查看其manifest文件,发现其中注册了一个名叫LeakSentryInstaller的ContentProvider,因此其onCreate方法会在Application#onCreate之前得到执行,原因如下
// ActivityThread.java
private void handleBindApplication() {
...
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
}
mInstrumentation.callApplicationOnCreate(app);
}
private void installContentProviders(...) {
installProvider(...);
}
private IActivityManager.ContentProviderHolder installProvider(...) {
ContentProvider localProvider = null;
localProvider = (ContentProvider)cl.loadClass(info.name).newInstance();
localProvider.attachInfo(c, info);
}
// ContentProvider.java
private void attachInfo(...) {
if (mContext == null) {
...
ContentProvider.this.onCreate();
}
}
搞清楚了入口以后,看看LeakSentryInstaller#onCreate都干了些什么
// LeakSentryInstaller.kt
override fun onCreate(): Boolean {
CanaryLog.logger = DefaultCanaryLog()
val application = context!!.applicationContext as Application
InternalLeakSentry.install(application)
return true
}
internal object InternalLeakSentry {
init {
listener = try {
val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary")
leakCanaryListener.getDeclaredField("INSTANCE").get(null) as LeakSentryListener
} catch (ignored: Throwable) {
LeakSentryListener.None
}
}
}
fun install(application: Application) {
...
InternalLeakSentry.application = application
val configProvider = { LeakSentry.config }
ActivityDestroyWatcher.install(application, refWatcher, configProvider)
FragmentDestroyWatcher.install(application, refWatcher, configProvider)
listener.onLeakSentryInstalled(application)
}
object LeakSentry {
data class Config(
val enabled: Boolean = InternalLeakSentry.isDebuggableBuild,
val watchActivities: Boolean = true,
val watchFragments: Boolean = true,
val watchFragmentViews: Boolean = true,
val watchDurationMillis: Long = TimeUnit.SECONDS.toMillis(5))
@Volatile
var config: Config = if (isInstalled) Config() else Config(enabled = false)
val refWatcher
get() = InternalLeakSentry.refWatcher
val isInstalled
get() = InternalLeakSentry.isInstalled
fun manualInstall(application: Application) = InternalLeakSentry.install(application)
}
onCreate内部调用了InternalLeakSentry#install,在其init代码块设置了监听器当LeakCanary被依赖时会设置成InternalLeakCanary实例,不然就是一个空实现,install内部主要就是调用了两个Watch#install
ActivityDestroyWatcher#install
// ActivityDestroyWatcher.kt
internal class ActivityDestroyWatcher private constructor(
private val refWatcher: RefWatcher,
private val configProvider: () -> Config) {
private val lifecycleCallbacks = object : ActivityLifecycleCallbacksAdapter() {
override fun onActivityDestroyed(activity: Activity) {
if (configProvider().watchActivities) {
refWatcher.watch(activity)
}
}
}
companion object {
fun install(
application: Application,
refWatcher: RefWatcher,
configProvider: () -> Config) {
val activityDestroyWatcher =
ActivityDestroyWatcher(refWatcher, configProvider)
application.registerActivityLifecycleCallbacks(activityDestroyWatcher.lifecycleCallbacks)
}
}
}
内部注册了一个Activity生命周期回调,当onDestory事件来临时由于默认的config.watchActivities = true,因此refWatcher#water将被调用
class RefWatcher constructor(
private val clock: Clock,
private val checkRetainedExecutor: Executor,
private val onReferenceRetained: () -> Unit,
private val isEnabled: () -> Boolean = { true }) {
private val watchedReferences = mutableMapOf<String, KeyedWeakReference>()
private val retainedReferences = mutableMapOf<String, KeyedWeakReference>()
private val queue = ReferenceQueue<Any>()
val hasRetainedReferences: Boolean
@Synchronized get() {
removeWeaklyReachableReferences()
return retainedReferences.isNotEmpty()
}
val hasWatchedReferences: Boolean
@Synchronized get() {
removeWeaklyReachableReferences()
return retainedReferences.isNotEmpty() || watchedReferences.isNotEmpty()
}
val retainedKeys: Set<String>
@Synchronized get() {
removeWeaklyReachableReferences()
return HashSet(retainedReferences.keys)
}
@Synchronized
fun watch(watchedReference: Any) {
watch(watchedReference, "")
}
@Synchronized
fun watch(
watchedReference: Any,
referenceName: String) {
if (!isEnabled()) {
return
}
removeWeaklyReachableReferences()
val key = UUID.randomUUID()
.toString()
val watchUptimeMillis = clock.uptimeMillis()
val reference =
KeyedWeakReference(watchedReference, key, referenceName, watchUptimeMillis, queue)
watchedReferences[key] = reference
checkRetainedExecutor.execute {
moveToRetained(key)
}
}
@Synchronized
private fun moveToRetained(key: String) {
removeWeaklyReachableReferences()
val retainedRef = watchedReferences.remove(key)
if (retainedRef != null) {
retainedReferences[key] = retainedRef
onReferenceRetained()
}
}
@Synchronized
fun removeRetainedKeys(keysToRemove: Set<String>) {
retainedReferences.keys.removeAll(keysToRemove)
}
@Synchronized
fun clearWatchedReferences() {
watchedReferences.clear()
retainedReferences.clear()
}
private fun removeWeaklyReachableReferences() {
var ref: KeyedWeakReference?
do {
ref = queue.poll() as KeyedWeakReference?
if (ref != null) {
val removedRef = watchedReferences.remove(ref.key)
if (removedRef == null) {
retainedReferences.remove(ref.key)
}
}
} while (ref != null)
}
}
watch方法主要分为如下几步
- 当isEnabled被设置成false,那么watch将会直接返回,该值取自于config
- 移除掉那些已经在队列里面的弱引用,一开始肯定没有先跳过
- 创建一个KeyedWeakReference实例(派生自WeakReference),传入queue,当被观察的对象被回收掉以后会将弱引用对象放入该队列中去
- 将弱引用对象放入watchedReferences中
- 延迟一定时间后(默认为5秒,取自于config)调用moveToRetained
moveToRetained首先调用了removeWeaklyReachableReferences(),该方法将那些已经放到队列中的弱引用对象从watchedReferences中移除(存在队列中就表示该对象已经被回收了不可能发生内存泄露),后面的retainedReferences#remove是为了将上次保留的对象删除(因为本次它已经被回收了)。接着如果retainedRef!=null,那么就说明该对象还没有被回收,就加入到retainedReferences中,并回调listener#onReferenceRetained
FragmentDestroyWatcher#install
internal interface FragmentDestroyWatcher {
fun watchFragments(activity: Activity)
companion object {
private const val SUPPORT_FRAGMENT_CLASS_NAME = "androidx.fragment.app.Fragment"
fun install(
application: Application,
refWatcher: RefWatcher,
configProvider: () -> LeakSentry.Config) {
val fragmentDestroyWatchers = mutableListOf<FragmentDestroyWatcher>()
if (SDK_INT >= O) {
fragmentDestroyWatchers.add(AndroidOFragmentDestroyWatcher(refWatcher, configProvider))
}
if (classAvailable(SUPPORT_FRAGMENT_CLASS_NAME)) {
fragmentDestroyWatchers.add(SupportFragmentDestroyWatcher(refWatcher, configProvider))
}
if (fragmentDestroyWatchers.size == 0) {
return
}
application.registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacksAdapter() {
override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?) {
for (watcher in fragmentDestroyWatchers) {
watcher.watchFragments(activity)
}
}
})
}
private fun classAvailable(className: String): Boolean {
return try {
Class.forName(className)
true
} catch (e: ClassNotFoundException) {
false
}
}
}
}
首先FragmentDestroyWatcher只支持Android8及以上或者是AndroidX,还是监听了Activity声明周期不过这次监听onCreate,先看看AndroidOFragmentDestroyWatcher#watchFragments
AndroidOFragmentDestroyWatcher#watchFragments
internal class AndroidOFragmentDestroyWatcher(
private val refWatcher: RefWatcher,
private val configProvider: () -> Config
) : FragmentDestroyWatcher {
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentViewDestroyed(
fm: FragmentManager,
fragment: Fragment) {
val view = fragment.view
if (view != null && configProvider().watchFragmentViews) {
refWatcher.watch(view)
}
}
override fun onFragmentDestroyed(
fm: FragmentManager,
fragment: Fragment) {
if (configProvider().watchFragments) {
refWatcher.watch(fragment)
}
}
}
override fun watchFragments(activity: Activity) {
val fragmentManager = activity.fragmentManager
fragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
}
}
内部注册了Fragment声明周期回调,由于该方法只有在API26及以上才有,因此前面判断了Android O,接着当Fragment被销毁后会分别调用refWatcher.watch(view)、refWatcher.watch(fragment),这里面的逻辑上文已经说过了
AndroidOFragmentDestroyWatcher#watchFragments
internal class SupportFragmentDestroyWatcher(
private val refWatcher: RefWatcher,
private val configProvider: () -> Config) : FragmentDestroyWatcher {
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentViewDestroyed(
fm: FragmentManager,
fragment: Fragment) {
val view = fragment.view
if (view != null && configProvider().watchFragmentViews) {
refWatcher.watch(view)
}
}
override fun onFragmentDestroyed(
fm: FragmentManager,
fragment: Fragment) {
if (configProvider().watchFragments) {
refWatcher.watch(fragment)
}
}
}
override fun watchFragments(activity: Activity) {
if (activity is FragmentActivity) {
val supportFragmentManager = activity.supportFragmentManager
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
}
}
}
内部逻辑与AndroidOFragmentDestroyWatcher一样,只是获取的是supportFragmentManager
总结
根据源码可以看出LeakSentry内部使用弱引用保存被观察对象,在指定时间后如果还未被回收就可以认为该对象可能发生内存泄露,其默认会自动观察销毁的Activity、fragment及其内部View,同时也可以手动使用LeakSentry.refWatcher.watch(obj)来观察任意不再需要的对象,然后在代码中通过调用LeakSentry.refWatcher.retainedKeys.size查看还有几个被观察对象还未被释放