LeakCanary简单分析-爱代码爱编程
在使用LeakCanary的时候要引入:
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.4'
debugImplementation : debugImplementation 只在debug模式的编译和最终的debug apk打包时有效
LeakCanary的初始化是利用ContentProvider进行初始化的,
<provider
android:name="leakcanary.internal.AppWatcherInstaller$MainProcess"
android:authorities="${applicationId}.leakcanary-installer"
android:enabled="@bool/leak_canary_watcher_auto_install"
android:exported="false" />
ContentProvider是在Application的onCreate的前面执行的,也就是在App启动的时候已经初始化好了。具体的ContentProvider是在什么时候执行的可以参考博客。
下面是AppWatcherInstaller的ContentProvider的onCreate代码:
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
AppWatcher.manualInstall(application)
return true
}
AppWatcher是一个单例类只要作用:
The entry point API for using [ObjectWatcher] in an Android app. [AppWatcher.objectWatcher] is
* in charge of detecting retained objects, and [AppWatcher] is auto configured on app start to
* pass it activity and fragment instances. Call [ObjectWatcher.watch] on [objectWatcher] to
* watch any other object that you expect to be unreachable.
在Android应用中使用[ObjectWatcher]的入口点API。 *[AppWatcher.objectWatcher]负责检测保留的对象,[AppWatcher]在应用程序启动时自动配置为通过它的Activity和Fragment实例。
调用[objectWatcher]上的[ObjectWatcher.watch]以监视您期望无法访问的任何其他对象。
/**
* [AppWatcher] is automatically installed in the main process on startup. You can
* disable this behavior by overriding the `leak_canary_watcher_auto_install` boolean resource:
*
* ```
* <?xml version="1.0" encoding="utf-8"?>
* <resources>
* <bool name="leak_canary_watcher_auto_install">false</bool>
* </resources>
* ```
*
* If you disabled automatic install then you can call this method to install [AppWatcher].
*/
fun manualInstall(application: Application) {
InternalAppWatcher.install(application)
}
这是在values.xml中的一个字段
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="leak_canary_watcher_auto_install">true</bool>
</resources>
下面就是install的代码:
fun install(application: Application) {
checkMainThread()//检查是否在主线程,如果不是抛出异常
if (this::application.isInitialized) {//判断这个lateinit的属性是否被复制
return
}
SharkLog.logger = DefaultCanaryLog()//设置日志打印
InternalAppWatcher.application = application
val configProvider = { AppWatcher.config }//设置config
//下面这两个就是观察Activity和Fragment是否泄漏的
ActivityDestroyWatcher.install(application, objectWatcher, configProvider)
FragmentDestroyWatcher.install(application, objectWatcher, configProvider)
onAppWatcherInstalled(application)
}
data class Config(
/**
* Whether AppWatcher should automatically watch destroyed activity instances.
*
* Defaults to true.
*/
val watchActivities: Boolean = true,
/**
* Whether AppWatcher should automatically watch destroyed fragment instances.
*
* Defaults to true.
*/
val watchFragments: Boolean = true,
/**
* Whether AppWatcher should automatically watch destroyed fragment view instances.
*
* Defaults to true.
*/
val watchFragmentViews: Boolean = true,
/**
* Whether AppWatcher should automatically watch cleared [androidx.lifecycle.ViewModel]
* instances.
*
* Defaults to true.
*/
val watchViewModels: Boolean = true,
/**
* How long to wait before reporting a watched object as retained.
*
* Default to 5 seconds.
*/
val watchDurationMillis: Long = TimeUnit.SECONDS.toMillis(5),
/**
* Deprecated, this didn't need to be a part of the API.
* Used to indicate whether AppWatcher should watch objects (by keeping weak references to
* them). Currently a no-op.
*
* If you do need to stop watching objects, simply don't pass them to [objectWatcher].
*/
@Deprecated("This didn't need to be a part of LeakCanary's API. No-Op.")
val enabled: Boolean = true
)
下面我们先分析这个Activity的写泄漏:主要是给application的registerActivityLifecycleCallbacks添加一个监听,
internal class ActivityDestroyWatcher private constructor(
private val objectWatcher: ObjectWatcher,
private val configProvider: () -> Config
) {
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityDestroyed(activity: Activity) {
if (configProvider().watchActivities) {
objectWatcher.watch(
activity, "${activity::class.java.name} received Activity#onDestroy() callback"
)
}
}
}
companion object {
fun install(
application: Application,
objectWatcher: ObjectWatcher,
configProvider: () -> Config
) {
val activityDestroyWatcher =
ActivityDestroyWatcher(objectWatcher, configProvider)
application.registerActivityLifecycleCallbacks(activityDestroyWatcher.lifecycleCallbacks)
}
}
}
下面就是在回调了Activity的onDestroy的方法后执行的内容:这个地方就是创建一个弱引用对象,进行观察,当执行完GC之后是否还存在,判断是否泄漏
/**
* Watches the provided [watchedObject].
*
* @param description Describes why the object is watched.
*/
@Synchronized fun watch(
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
checkRetainedExecutor.execute {
moveToRetained(key)
}
}
@Synchronized private fun moveToRetained(key: String) {
removeWeaklyReachableObjects()
val retainedRef = watchedObjects[key]
if (retainedRef != null) {
retainedRef.retainedUptimeMillis = clock.uptimeMillis()
onObjectRetainedListeners.forEach { it.onObjectRetained() }
}
}
这个地方的onObjectRetained()方法是InternalLeakCanary中的onObjectRetained()方法可以看到调用的时候HeapDumpTrigger对象的onObjectRetained()方法下面看下这个方法
fun onObjectRetained() {
scheduleRetainedObjectCheck(
reason = "found new object retained",
rescheduling = false
)
}
private fun checkRetainedObjects(reason: String) {
val config = configProvider()
// A tick will be rescheduled when this is turned back on.
if (!config.dumpHeap) {
SharkLog.d { "Ignoring check for retained objects scheduled because $reason: LeakCanary.Config.dumpHeap is false" }
return
}
//弱引用对象中保存的没有回收的Activity的数量
var retainedReferenceCount = objectWatcher.retainedObjectCount
if (retainedReferenceCount > 0) {//数量大于0执行GC,执行GC后再获取一次个数
gcTrigger.runGc()
retainedReferenceCount = objectWatcher.retainedObjectCount
}
//这个地方是检查回收对象的数量是否超过定义的阀值(5)如果没有就直接返回
if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return
//判断是否连接了调试解调器,如果是就直接返回
if (!config.dumpHeapWhenDebugging && DebuggerControl.isDebuggerAttached) {
onRetainInstanceListener.onEvent(DebuggerIsAttached)
showRetainedCountNotification(
objectCount = retainedReferenceCount,
contentText = application.getString(
R.string.leak_canary_notification_retained_debugger_attached
)
)
scheduleRetainedObjectCheck(
reason = "debugger is attached",
rescheduling = true,
delayMillis = WAIT_FOR_DEBUG_MILLIS
)
return
}
val now = SystemClock.uptimeMillis()
val elapsedSinceLastDumpMillis = now - lastHeapDumpUptimeMillis
//如果时间小于预定义的5秒就Notification并且返回
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(
reason = "previous heap dump was ${elapsedSinceLastDumpMillis}ms ago (< ${WAIT_BETWEEN_HEAP_DUMPS_MILLIS}ms)",
rescheduling = true,
delayMillis = WAIT_BETWEEN_HEAP_DUMPS_MILLIS - elapsedSinceLastDumpMillis
)
return
}
SharkLog.d { "Check for retained objects found $retainedReferenceCount objects, dumping the heap" }
dismissRetainedCountNotification()
//把堆中的信息保存到文件
dumpHeap(retainedReferenceCount, retry = true)
}
private fun dumpHeap(
retainedReferenceCount: Int,
retry: Boolean
) {
saveResourceIdNamesToMemory()
val heapDumpUptimeMillis = SystemClock.uptimeMillis()
KeyedWeakReference.heapDumpUptimeMillis = heapDumpUptimeMillis
val heapDumpFile = heapDumper.dumpHeap()
if (heapDumpFile == null) {
if (retry) {
SharkLog.d { "Failed to dump heap, will retry in $WAIT_AFTER_DUMP_FAILED_MILLIS ms" }
scheduleRetainedObjectCheck(
reason = "failed to dump heap",
rescheduling = true,
delayMillis = WAIT_AFTER_DUMP_FAILED_MILLIS
)
} else {
SharkLog.d { "Failed to dump heap, will not automatically retry" }
}
showRetainedCountNotification(
objectCount = retainedReferenceCount,
contentText = application.getString(
R.string.leak_canary_notification_retained_dump_failed
)
)
return
}
lastDisplayedRetainedObjectCount = 0
lastHeapDumpUptimeMillis = SystemClock.uptimeMillis()
objectWatcher.clearObjectsWatchedBefore(heapDumpUptimeMillis)
//保存到文件后分析这个hprof文件
HeapAnalyzerService.runAnalysis(application, heapDumpFile)
}
fun runAnalysis(
context: Context,
heapDumpFile: File
) {
//启动一个前台服务分析堆文件
val intent = Intent(context, HeapAnalyzerService::class.java)
intent.putExtra(HEAPDUMP_FILE_EXTRA, heapDumpFile)
startForegroundService(context, intent)
}
下面就是hprof文件的分析了,LeakCanary用的Shark进行分析的。shark官网
LeakCanary自动检测以下对象的泄漏:
- 销毁
Activity
实例 - 销毁
Fragment
实例 destroy fragment View
实例- 清除
ViewModel
实例
它就会通过4个步骤自动检测并报告内存泄漏:
- 检测保留的对象。
- 转储堆。
- 分析堆。
- 分类泄漏。
详细的流程可以去官网看下,地址为https://square.github.io/leakcanary/fundamentals-how-leakcanary-works/
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/qqqq245425070/article/details/111088678