LeakCanary2.6抽丝剥茧-源码分析
旧事重提-1.6.3版本和2.6版本的对比
作为一个小Android,之前分析项过目中LeakCanary1.6.3的源码,今天在好奇心的驱使下,刷新了下maven发现,LeakCanary已经更新到2.6版本,今天对2.6的版本也进行源码的解析。
内存泄露分析原理:还是不变的-可达性分析法
:根据是否被GC Root引用确认是否是垃圾对象要被GC回收
2.6版本跟踪内存泄露的核心原理和1.6.3版本是一样的,依赖核心理论-利用weakReference中的数据在gc后是否被添加到ReferenceQueue队列中
使用上的区别
- 1.6.3使用需要添加依赖和在Application进行注册
gradle的依赖:
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3'
Application的调用
public class ExampleApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//注册
LeakCanary.install(this);
}
}
- 2.6只需要在gradle中添加下依赖就行
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.6'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:2.6.'
实现语言的区别
- 1.6.3版本是使用Java语言
- 2.x版本开始都是使用kotlin语言
路径分析库的区别
- 1.6.3版本内存泄漏引用路径分析库是
haha
库 - 2.6版本内存泄漏引用路径分析库替换成
shark
库,据说减少了90%内存占用,速度提升了6倍
注册的区别
- 1.6.3版本是需要开发者手动在
Application.onCreate()
方法中进行注册 - 2.6版本LeakCanary是使用
ContentProvider
直接配置在AndroidManifest.xml(不需要手动添加,apk打包会自动配置到)
开始解刨
根据上面的描述,2.6版本是LeakCanary 自动通过ContentProvider
注册监听(ContentProvider 会在应用启动前创建)
可以在
源码如下:
<provider
android:name="leakcanary.internal.AppWatcherInstaller$MainProcess"
android:authorities="${applicationId}.leakcanary-installer"
android:enabled="@bool/leak_canary_watcher_auto_install"
android:exported="false" />
找到了个入口点,AppWatcherInstaller
internal sealed class AppWatcherInstaller : ContentProvider() {
......省略部分代码
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
AppWatcher.manualInstall(application)
return true
}
.....省略部分代码
}
查看AppWatcher.kt的manualInstall方法
object 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()
}
// LaekCanary的预设置,通过反射 'leakcanary.internal.InternalLeakCanary'这个类
LeakCanaryDelegate.loadLeakCanary(application)
//配置监听(activity,fragment,rootview,service)
watchersToInstall.forEach {
it.install()
}
}
.....省略部分代码
}
前面的kotlin函数参数watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)
这边实现了activity,fragment,rootview,service的四个监听器,相比1.6.3版本,2.6版本新增了rootview,service的这两个watcher
fun appDefaultWatchers(
application: Application,
reachabilityWatcher: ReachabilityWatcher = objectWatcher
): List<InstallableWatcher> {
return listOf(
ActivityWatcher(application, reachabilityWatcher),
FragmentAndViewModelWatcher(application, reachabilityWatcher),
RootViewWatcher(reachabilityWatcher),
ServiceWatcher(reachabilityWatcher)
)
}
ActivityWatcher,activity的监听还是和1.6.3版本一样是采用监听activity的生命周期,在Destroy的时候,传给ObjectWatcher,做内存泄露的检查,ObjectWatcher在后面会讲到
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)
}
}
FragmentAndViewModelWatcher在处理fragment的内存泄露,相对在1.6.3版本,LeakCanary针对android.app.Fragment 、support.v4.app.Fragment、androidx.fragment.app.Fragment 三种fragment,分别通过AndroidOFragmentDestroyWatcher、AndroidSupportFragmentDestroyWatcher、AndroidXFragmentDestroyWatcher来进行监听
Fragment的监听,这边以AndroidOFragmentDestroyWatcher来进行讲解,AndroidSupportFragmentDestroyWatcher、AndroidXFragmentDestroyWatcher的流程源码是差不多的
internal class AndroidOFragmentDestroyWatcher(
private val reachabilityWatcher: ReachabilityWatcher
) : (Activity) -> Unit {
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentViewDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
val view = fragment.view
if (view != null) {
//在fragment的声明周期执行时,将View对象传给ObjectWatcher
reachabilityWatcher.expectWeaklyReachable(
view, "${fragment::class.java.name} received Fragment#onDestroyView() callback " +
"(references to its views should be cleared to prevent leaks)"
)
}
}
override fun onFragmentDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
//在fragment的声明周期执行时,将fragment对象传给ObjectWatcher
reachabilityWatcher.expectWeaklyReachable(
fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
)
}
}
override fun invoke(activity: Activity) {
val fragmentManager = activity.fragmentManager
fragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
}
}
AndroidXFragmentDestroyWatcher这个比较特殊一点是:invoke方法是多了一个viewmodel的监听,
supportFragmentManager,监听Fragment的声明周期,对于Fragment,在onFragmentCreated回调中注册监听,在ViewModel的onCleared回调中监控ViewModel,
在onFragmentDestroyed监听fragment,在onFragmentViewDestroyed监听view
override fun invoke(activity: Activity) {
if (activity is FragmentActivity) {
val supportFragmentManager = activity.supportFragmentManager
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
ViewModelClearedWatcher.install(activity, reachabilityWatcher)
}
}
fragment又是依赖于activity:
class FragmentAndViewModelWatcher(
private val application: Application,
private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {
private val fragmentDestroyWatchers: List<(Activity) -> Unit> = run {
val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()
if (SDK_INT >= O) {
fragmentDestroyWatchers.add(
AndroidOFragmentDestroyWatcher(reachabilityWatcher)
)
}
//Androidx的fragment
getWatcherIfAvailable(
ANDROIDX_FRAGMENT_CLASS_NAME,
ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
reachabilityWatcher
)?.let {
fragmentDestroyWatchers.add(it)
}
//suport的fragment
getWatcherIfAvailable(
ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,
ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
reachabilityWatcher
)?.let {
fragmentDestroyWatchers.add(it)
}
fragmentDestroyWatchers
}
//最终还是依赖于activity的声明周期进行监听,这边的监听是在onActivityCreated这个生命周期方法执行的时候
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?
) {
for (watcher in fragmentDestroyWatchers) {
watcher(activity)
}
}
}
override fun install() {
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
override fun uninstall() {
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
}
//反射的方式获取AndroidSupportFragmentDestroyWatcher、AndroidXFragmentDestroyWatcher来进行监听
private fun getWatcherIfAvailable(
fragmentClassName: String,
watcherClassName: String,
reachabilityWatcher: ReachabilityWatcher
): ((Activity) -> Unit)? {
return if (classAvailable(fragmentClassName) &&
classAvailable(watcherClassName)
) {
val watcherConstructor =
Class.forName(watcherClassName).getDeclaredConstructor(ReachabilityWatcher::class.java)
@Suppress("UNCHECKED_CAST")
watcherConstructor.newInstance(reachabilityWatcher) as (Activity) -> Unit
} else {
null
}
}
......省略了部分代码
}
RootViewWatcher:view的内存泄露监听,必须在api是19或者19以上的系统,才支持,通过OnAttachStateChangeListener.onViewDetachedFromWindow()来监听view对象是否内存泄露
class RootViewWatcher(
private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {
override fun install() {
if (Build.VERSION.SDK_INT < 19) {
return
}
swapViewManagerGlobalMViews { mViews ->
object : ArrayList<View>(mViews) {
override fun add(element: View): Boolean {
onRootViewAdded(element)
return super.add(element)
}
}
}
}
private fun onRootViewAdded(rootView: View) {
rootView.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
val watchDetachedView = Runnable {
reachabilityWatcher.expectWeaklyReachable(
rootView, "${rootView::class.java.name} received View#onDetachedFromWindow() callback"
)
}
override fun onViewAttachedToWindow(v: View) {
mainHandler.removeCallbacks(watchDetachedView)
}
override fun onViewDetachedFromWindow(v: View) {
mainHandler.post(watchDetachedView)
}
})
}
}
ServiceWatcher:通过hook mH回调的service的onDestroy的方法,将该service保存到activityThreadServices。hook AMS,当调用了serviceDoneExecuting方法时,判断service是否出现泄漏
override fun install() {
checkMainThread()
check(uninstallActivityThreadHandlerCallback == null) {
"ServiceWatcher already installed"
}
check(uninstallActivityManager == null) {
"ServiceWatcher already installed"
}
try {
//hook mH 的callback
swapActivityThreadHandlerCallback { mCallback ->
uninstallActivityThreadHandlerCallback = {
swapActivityThreadHandlerCallback {
mCallback
}
}
Handler.Callback { msg ->
///当调用了service 的onDestroy时
if (msg.what == STOP_SERVICE) {
val key = msg.obj as IBinder
activityThreadServices[key]?.let {
//将这个service通过弱引用的方式保存到servicesToBeDestroyed中
onServicePreDestroy(key, it)
}
}
mCallback?.handleMessage(msg) ?: false
}
}
//继续hook,这里hook的是ActivityManagerService
swapActivityManager { activityManagerInterface, activityManagerInstance ->
uninstallActivityManager = {
swapActivityManager { _, _ ->
activityManagerInstance
}
}
//动态代理的方式
Proxy.newProxyInstance(
activityManagerInterface.classLoader, arrayOf(activityManagerInterface)
) { _, method, args ->
//当调用serviceDoneExecuting方法时,观察这个service的泄漏情况
if (METHOD_SERVICE_DONE_EXECUTING == method.name) {
//通过token获取service
val token = args!![0] as IBinder
if (servicesToBeDestroyed.containsKey(token)) {
//观察service泄漏情况
onServiceDestroyed(token)
}
}
try {
if (args == null) {
method.invoke(activityManagerInstance)
} else {
method.invoke(activityManagerInstance, \\*args)
}
} catch (invocationException: InvocationTargetException) {
throw invocationException.targetException
}
}
}
} catch (ignored: Throwable) {
SharkLog.d(ignored) { "Could not watch destroyed services" }
}
}
private fun onServicePreDestroy(
token: IBinder,
service: Service
) {
servicesToBeDestroyed[token] = WeakReference(service)
}
private fun onServiceDestroyed(token: IBinder) {
servicesToBeDestroyed.remove(token)?.also { serviceWeakReference ->
serviceWeakReference.get()?.let { service ->
//传给ObjectWatcher去检查内存泄露
reachabilityWatcher.expectWeaklyReachable(
service, "${service::class.java.name} received Service#onDestroy() callback"
)
}
}
}
LeakCanaryDelegate.loadLeakCanary(application)
是LaekCanary的预设置,通过反射 'leakcanary.internal.InternalLeakCanary'这个类
InternalLeakCanary.invoke方法是对内存泄露后续对确认和路径分析进行 初始化
internal object LeakCanaryDelegate {
val loadLeakCanary by lazy {
try {
val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary")
leakCanaryListener.getDeclaredField("INSTANCE")
.get(null) as (Application) -> Unit
} catch (ignored: Throwable) {
NoLeakCanary
}
}
}
开始讲解ObjectWatcher:
class ObjectWatcher constructor(
private val clock: Clock,
private val checkRetainedExecutor: Executor,
//是否忽略
private val isEnabled: () -> Boolean = { true }
) : ReachabilityWatcher {
//保留对象的监听(内存泄露对象的通知监听)
private val onObjectRetainedListeners = mutableSetOf<OnObjectRetainedListener>()
//KeyedWeakReference的合集,用来存放可能内存泄露的KeyedWeakReference
private val watchedObjects = mutableMapOf<String, KeyedWeakReference>()
//弱引用对象被回收的数据存放队列
private val queue = ReferenceQueue<Any>()
......省略了部分代码
@Synchronized fun addOnObjectRetainedListener(listener: OnObjectRetainedListener) {
onObjectRetainedListeners.add(listener)
}
@Synchronized fun removeOnObjectRetainedListener(listener: OnObjectRetainedListener) {
onObjectRetainedListeners.remove(listener)
}
//核心方法, watchedObject:就是监听activity,fragment、view、service这些对象
@Synchronized override fun expectWeaklyReachable(
watchedObject: Any,
description: String
) {
//是否不进行内存泄露检查
if (!isEnabled()) {
return
}
//清除掉非内存泄露的对象
removeWeaklyReachableObjects()
//生成唯一key
val key = UUID.randomUUID()
.toString()
//监听时间
val watchUptimeMillis = clock.uptimeMillis()
//生成KeyedWeakReference对象
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集合中
watchedObjects[key] = reference
checkRetainedExecutor.execute {
moveToRetained(key)
}
}
.......省略部分代码
//传递这个内存泄露嫌疑的对象,回调给InternalLeakCanary进行手动gc,再一次确认
@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() {
do {
ref = queue.poll() as KeyedWeakReference?
if (ref != null) {
watchedObjects.remove(ref.key)
}
} while (ref != null)
}
}
解释上,上面onObjectRetainedListeners的回调为什么回回调到InternalLeakCanary中,前面我们提到LeakCanaryDelegate.loadLeakCanary(application)
是LeakCanary的预设置,通过反射 'leakcanary.internal.InternalLeakCanary'这个类,调用了invoke这个方法
internal object InternalLeakCanary : (Application) -> Unit, OnObjectRetainedListener {
......省略代码
override fun invoke(application: Application) {
_application = application
checkRunningInDebuggableBuild()
//这边添加了OnObjectRetainedListener的监听,让InternalLeakCanary实现了OnObjectRetainedListener接口
AppWatcher.objectWatcher.addOnObjectRetainedListener(this)
//创建AndroidHeapDumper对象,用来进行内存泄露分析的通知和toast提示
val heapDumper = AndroidHeapDumper(application, createLeakDirectoryProvider(application))
//gc和1.6.3版本一样的实现,只是代码是用kotlin写的
val gcTrigger = GcTrigger.Default
val configProvider = { LeakCanary.config }
val handlerThread = HandlerThread(LEAK_CANARY_THREAD_NAME)
handlerThread.start()
val backgroundHandler = Handler(handlerThread.looper)
//路径分析的触发器,手动gc的触发checkRetainedObjects()
heapDumpTrigger = HeapDumpTrigger(
application, backgroundHandler, AppWatcher.objectWatcher, gcTrigger, heapDumper,
configProvider
)
//activity的声明周期监听
application.registerVisibilityListener { applicationVisible ->
this.applicationVisible = applicationVisible
heapDumpTrigger.onApplicationVisibilityChanged(applicationVisible)
}
registerResumedActivityListener(application)
//动态增加LeakCanary的桌面图标
addDynamicShortcut(application)
// 日志输出,在Application.onCreate()执行后ß
mainHandler.post {
backgroundHandler.post {
SharkLog.d {
when (val iCanHasHeap = HeapDumpControl.iCanHasHeap()) {
is Yup -> application.getString(R.string.leak_canary_heap_dump_enabled_text)
is Nope -> application.getString(
R.string.leak_canary_heap_dump_disabled_text, iCanHasHeap.reason()
)
}
}
}
}
}
override fun onObjectRetained() = scheduleRetainedObjectCheck()
......省略代码
}
继之前的 ObjectWatcher的OnObjectRetainedListener.onObjectRetained() ,回调到InternalLeakCanary中实现的onObjectRetained() 方法
//转交给heapDumpTrigger去进行处理
fun scheduleRetainedObjectCheck() {
if (this::heapDumpTrigger.isInitialized) {
heapDumpTrigger.scheduleRetainedObjectCheck()
}
}
转到HeapDumpTrigger的scheduleRetainedObjectCheck()方法
internal class HeapDumpTrigger(
private val application: Application,
private val backgroundHandler: Handler,
private val objectWatcher: ObjectWatcher,
private val gcTrigger: GcTrigger,
private val heapDumper: HeapDumper,
private val configProvider: () -> Config
) {
.......省略部分代码
private fun checkRetainedObjects() {
val iCanHasHeap = HeapDumpControl.iCanHasHeap()
val config = configProvider()
if (iCanHasHeap is Nope) {
if (iCanHasHeap is NotifyingNope) {
// Before notifying that we can't dump heap, let's check if we still have retained object.
var retainedReferenceCount = objectWatcher.retainedObjectCount
if (retainedReferenceCount > 0) {
//触发GC
gcTrigger.runGc()
retainedReferenceCount = objectWatcher.retainedObjectCount
}
val nopeReason = iCanHasHeap.reason()
// 如果内存泄漏对象数量在阈值内,不生成dump文件分析
val wouldDump = !checkRetainedCount(
retainedReferenceCount, config.retainedVisibleThreshold, nopeReason
)
if (wouldDump) {
val uppercaseReason = nopeReason[0].toUpperCase() + nopeReason.substring(1)
onRetainInstanceListener.onEvent(DumpingDisabled(uppercaseReason))
showRetainedCountNotification(
objectCount = retainedReferenceCount,
contentText = uppercaseReason
)
}
} else {
SharkLog.d {
application.getString(
R.string.leak_canary_heap_dump_disabled_text, iCanHasHeap.reason()
)
}
}
return
}
var retainedReferenceCount = objectWatcher.retainedObjectCount
// 如果保留对象的数量大于0,进行一次手动的gc
if (retainedReferenceCount > 0) {
gcTrigger.runGc()
retainedReferenceCount = objectWatcher.retainedObjectCount
}
// 如果内存泄漏对象数量在阈值内,直接返回
if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return
val now = SystemClock.uptimeMillis()
val elapsedSinceLastDumpMillis = now - lastHeapDumpUptimeMillis
if (elapsedSinceLastDumpMillis < WAIT_BETWEEN_HEAP_DUMPS_MILLIS) {
onRetainInstanceListener.onEvent(DumpHappenedRecently)
showRetainedCountNotification(
objectCount = retainedReferenceCount,
contentText = application.getString(R.string.leak_canary_notification_retained_dump_wait)
)
scheduleRetainedObjectCheck(
delayMillis = WAIT_BETWEEN_HEAP_DUMPS_MILLIS - elapsedSinceLastDumpMillis
)
return
}
dismissRetainedCountNotification()
val visibility = if (applicationVisible) "visible" else "not visible"
dumpHeap(
retainedReferenceCount = retainedReferenceCount,
retry = true,
reason = "$retainedReferenceCount retained objects, app is $visibility"
)
}
private fun checkRetainedCount(
retainedKeysCount: Int,
retainedVisibleThreshold: Int,
nopeReason: String? = null
): Boolean {
//检查最新的保留对象数量(内存泄露对象)数量是否发生变化
val countChanged = lastDisplayedRetainedObjectCount != retainedKeysCount
lastDisplayedRetainedObjectCount = retainedKeysCount
//当数量是0,通知没有内存泄漏
if (retainedKeysCount == 0) {
if (countChanged) {
SharkLog.d { "All retained objects have been garbage collected" }
onRetainInstanceListener.onEvent(NoMoreObjects)
showNoMoreRetainedObjectNotification()
}
return true
}
val applicationVisible = applicationVisible
val applicationInvisibleLessThanWatchPeriod = applicationInvisibleLessThanWatchPeriod
if (countChanged) {
val whatsNext = if (applicationVisible) {
if (retainedKeysCount < retainedVisibleThreshold) {
"not dumping heap yet (app is visible & < $retainedVisibleThreshold threshold)"
} else {
if (nopeReason != null) {
"would dump heap now (app is visible & >=$retainedVisibleThreshold threshold) but $nopeReason"
} else {
"dumping heap now (app is visible & >=$retainedVisibleThreshold threshold)"
}
}
} else if (applicationInvisibleLessThanWatchPeriod) {
val wait =
AppWatcher.config.watchDurationMillis - (SystemClock.uptimeMillis() - applicationInvisibleAt)
if (nopeReason != null) {
"would dump heap in $wait ms (app just became invisible) but $nopeReason"
} else {
"dumping heap in $wait ms (app just became invisible)"
}
} else {
if (nopeReason != null) {
"would dump heap now (app is invisible) but $nopeReason"
} else {
"dumping heap now (app is invisible)"
}
}
SharkLog.d {
val s = if (retainedKeysCount > 1) "s" else ""
"Found $retainedKeysCount object$s retained, $whatsNext"
}
}
// 如果内存泄露对象数量右边,且当前应用是可见的(在前台显示),则显示数量通知
if (retainedKeysCount < retainedVisibleThreshold) {
if (applicationVisible || applicationInvisibleLessThanWatchPeriod) {
if (countChanged) {
onRetainInstanceListener.onEvent(BelowThreshold(retainedKeysCount))
}
showRetainedCountNotification(
objectCount = retainedKeysCount,
contentText = application.getString(
R.string.leak_canary_notification_retained_visible, retainedVisibleThreshold
)
)
scheduleRetainedObjectCheck(
delayMillis = WAIT_FOR_OBJECT_THRESHOLD_MILLIS
)
return true
}
}
return false
}
//计划对保留的对象进行进步一步检查
fun scheduleRetainedObjectCheck(
delayMillis: Long = 0L
) {
val checkCurrentlyScheduledAt = checkScheduledAt
if (checkCurrentlyScheduledAt > 0) {
return
}
checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
backgroundHandler.postDelayed({
checkScheduledAt = 0
checkRetainedObjects()
}, delayMillis)
}
//通知提示没有更多的内存泄露信息
private fun showNoMoreRetainedObjectNotification() {
backgroundHandler.removeCallbacks(scheduleDismissRetainedCountNotification)
if (!Notifications.canShowNotification) {
return
}
val builder = Notification.Builder(application)
.setContentTitle(
application.getString(R.string.leak_canary_notification_no_retained_object_title)
)
.setContentText(
application.getString(
R.string.leak_canary_notification_no_retained_object_content
)
)
.setAutoCancel(true)
.setContentIntent(NotificationReceiver.pendingIntent(application, CANCEL_NOTIFICATION))
val notification =
Notifications.buildNotification(application, builder, LEAKCANARY_LOW)
notificationManager.notify(R.id.leak_canary_notification_retained_objects, notification)
backgroundHandler.postDelayed(
scheduleDismissRetainedCountNotification, DISMISS_NO_RETAINED_OBJECT_NOTIFICATION_MILLIS
)
}
//通知告知有多少个内存泄露的信息
private fun showRetainedCountNotification(
objectCount: Int,
contentText: String
) {
backgroundHandler.removeCallbacks(scheduleDismissRetainedCountNotification)
if (!Notifications.canShowNotification) {
return
}
@Suppress("DEPRECATION")
val builder = Notification.Builder(application)
.setContentTitle(
application.getString(R.string.leak_canary_notification_retained_title, objectCount)
)
.setContentText(contentText)
.setAutoCancel(true)
.setContentIntent(NotificationReceiver.pendingIntent(application, DUMP_HEAP))
val notification =
Notifications.buildNotification(application, builder, LEAKCANARY_LOW)
notificationManager.notify(R.id.leak_canary_notification_retained_objects, notification)
}
.......省略部分代码
}
通过以上的代码,可以看出HeapDumpTrigger实际上做了两件事
- 通过
objectWatcher.retainedObjectCount
的数量和阀值进行对比,判断是否需要生成dump文件 - 通过gc再一次生成,再一次确认了内存泄露的数量,即
objectWatcher.retainedObjectCount
值,确实是否需要dump文件和通知
这也是和1.6.3版本不一样的地方,旧版本是只要有泄露都会进行dump
最后dump的过程是和旧版基本是一样的,这边不做分析了。
可以参考下时序图:
回顾
- LeakCanary是如何简化了sdk的接入?
- 2.6版本相对1.6.3版本,只需要一行依赖配置代码即可,2.6采用ContentProvider,ContentProvider的onCreate的调用时机是在application onCreate之前调用的,减少了接入的成本
- 通过占位符的方式,简化了接入方在manifest文件上的接入成本,在编译打包的时候,会将
AppWatcherInstaller
合并到AndroidManifest中
- LeakCanary 触发去判断是否存在内存泄露的时机
- Activity:通过在Application中注册registerActivityLifecycleCallbacks绑定Activity生命周期回调,并在onActivityDestroyed回调中监控Activity
- Fragment:通过在Application中注册registerActivityLifecycleCallbacks绑定Activity生命周期回调,并在onActivityCreated回调中,通过在Activity中注册注册FragmentLifecycleCallbacks回调,并在onFragmentDestroyed回调时,监控fragment或者view。androidx的frogment是 针对AndroidX库中的Activity,对于Activity,在onActivityCreated回调中注册监听,对于Fragment,在onFragmentCreated回调中注册监听,在ViewModel的onCleared回调中监控ViewModel
- View:只作用于android>=19, 通过View.addOnAttachStateChangeListener注册view的声明周期,并在onViewDetachedFromWindow()来监听view对象是否内存泄露
- Service:通过hook mH回调的service的onDestroy的方法,将该service保存到activityThreadServices。hook AMS,当调用了serviceDoneExecuting方法时,判断service是否出现泄漏
- 判断内存泄露的原理
- 是利用了WeakRefrence + RefrenceQueue的机制(仅被弱引用持有的对象,当对象被回收时,会存入到引用队列中),从引用队列中不断的获取对象,将已确认被GC的对象剔除,剩余未被回收的对象则定义为可能泄露的对象,当达到一定的判断条件时,通知用户内存泄露