LeakCanary原理解析
LeakCanary是square公司开源的一个内存泄露检测的开源库。
理论
理论一:
引用分类:
- 强引用:强引用还存在,垃圾收集器永远不会回收掉被引用的对象。宁愿抛出OOM异常也不会回收。
- 软引用:(SoftReference)在JVM将要内存不足时,会进行一次GC,这次GC会回收软引用对象。内存充足时,不会回收软引用。
- 弱引用: (WeakReference)在JVM发生GC时,无论内存是否足够,都会回收弱引用。
- 虚引用:(PhantomReference)虚引用时极其不稳定,被引用的对象随时被回收。这个引用存在的唯一目的就是在这个对象被收集器回收时收到一个系统通知,被虚引用关联的对象,和其生存时间完全没关系。PhantomReference表示虚引用,需要搭配ReferenceQueue使用,检测对象回收情况。
理论二:
在声明一个WeakReference
对象同时,传入一个ReferenceQueue
作为构造参数时,那么当 WeakReference
持有的对象被 GC 回收时,JVM 就会把这个弱引用存入与之关联的引用队列之中。
理论三:
ContentProvider
会被在应用启动的时候自动初始化。
理论四:熟悉装饰者模式、策略模式。
解析
先看是如何初始化的:
在LeakCanary
里的清单文件里面有配置provider
标签,如下:
<provider
android:name="leakcanary.internal.AppWatcherInstaller$MainProcess"
android:authorities="${applicationId}.leakcanary-installer"
android:enabled="@bool/leak_canary_watcher_auto_install"
android:exported="false"/>
再看声明的AppWatcherInstaller
类,是会伴随app启动自动初始化的。
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
}
}
里面调用了AppWatcher.manualInstall(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) {
//dubug模式安装鲨鱼 见官网介绍
LogcatSharkLog.install()
}
// Requires AppWatcher.objectWatcher to be set
//延迟加载,会创建InternalLeakCanary的实例
LeakCanaryDelegate.loadLeakCanary(application)
//遍历注入对应4种类型的监听
watchersToInstall.forEach {
it.install()
}
}
其中appDefaultWatchers
会拿到默认需要检测的类型:Activity
、 Fragment
RootView
、 Service
。
fun appDefaultWatchers(
application: Application,
reachabilityWatcher: ReachabilityWatcher = objectWatcher
): List<InstallableWatcher> {
return listOf(
ActivityWatcher(application, reachabilityWatcher),
FragmentAndViewModelWatcher(application, reachabilityWatcher),
RootViewWatcher(reachabilityWatcher),
ServiceWatcher(reachabilityWatcher)
)
}
然后看很关键的一句it.install()
,InstallableWatcher
是个接口,来看看4种具体实现类是如何初始化的:
ActivityWatcher
class ActivityWatcher(
private val application: Application,
private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
//重写了ActivityLifecycleCallbacks方法,在activity销毁的时候加入监听中
override fun onActivityDestroyed(activity: Activity) {
//reachabilityWatcher 就是 ObjectWatch
reachabilityWatcher.expectWeaklyReachable(
activity, "${activity::class.java.name} received Activity#onDestroy() callback"
)
}
}
override fun install() {
//就是注册监听了registerActivityLifecycleCallbacks方法
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
override fun uninstall() {
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
}
}
对于ActivityWatcher
就是注册监听了registerActivityLifecycleCallbacks
方法,在activity走onDestroy方法回调的时候,将activity加入ObjectWatch来检测内存泄露。会执行ObjectWatch的expectWeaklyReachable
方法。
FragmentAndViewModelWatcher
class FragmentAndViewModelWatcher(
private val application: Application,
private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {
//这里创建了fragmentDestroyWatchers的集合
private val fragmentDestroyWatchers: List<(Activity) -> Unit> = run {
val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()
if (SDK_INT >= O) {
fragmentDestroyWatchers.add(
//添加AndroidOFragmentDestroyWatcher
AndroidOFragmentDestroyWatcher(reachabilityWatcher)
)
}
//添加AndroidXFragmentDestroyWatcher
getWatcherIfAvailable(
ANDROIDX_FRAGMENT_CLASS_NAME,
ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
reachabilityWatcher
)?.let {
fragmentDestroyWatchers.add(it)
}
//添加AndroidSupportFragmentDestroyWatcher
getWatcherIfAvailable(
ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,
ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
reachabilityWatcher
)?.let {
fragmentDestroyWatchers.add(it)
}
fragmentDestroyWatchers
}
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?
) {
for (watcher in fragmentDestroyWatchers) {
watcher(activity)
}
}
}
override fun install() {
//这里一样是注册了registerActivityLifecycleCallbacks
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
override fun uninstall() {
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
}
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
}
}
private fun classAvailable(className: String): Boolean {
return try {
Class.forName(className)
true
} catch (e: Throwable) {
false
}
}
companion object {
private const val ANDROIDX_FRAGMENT_CLASS_NAME = "androidx.fragment.app.Fragment"
private const val ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME =
"leakcanary.internal.AndroidXFragmentDestroyWatcher"
@Suppress("VariableNaming", "PropertyName")
private val ANDROID_SUPPORT_FRAGMENT_CLASS_NAME =
StringBuilder("android.").append("support.v4.app.Fragment")
.toString()
private const val ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME =
"leakcanary.internal.AndroidSupportFragmentDestroyWatcher"
}
}
总结下来就是将AndroidOFragmentDestroyWatcher、AndroidXFragmentDestroyWatcher、AndroidSupportFragmentDestroyWatcher各种情况创建的fragment加入一个集合中。
然后在onActivityCreated
回调中执行 watcher(activity)
方法。
这种写法kotlin的高级用法,上面那些***DestroyWatcher是都实现了(Activity) -> Unit接口,而(Activity) -> Unit这个在java中实现是Function1接口,要实现invoke接口,所以这里的watcher(activity)
就是调用invoke
方法(kotlin的语法太乱了)。
看invoke方法,上面三个都实现了,大同小异就看一个了AndroidXFragmentDestroyWatcher
:
override fun invoke(activity: Activity) {
if (activity is FragmentActivity) {
val supportFragmentManager = activity.supportFragmentManager
//注册了registerFragmentLifecycleCallbacks监听
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
// 检测 Activity 中的 ViewModel。
ViewModelClearedWatcher.install(activity, reachabilityWatcher)
}
}
内部重写了registerFragmentLifecycleCallbacks回调:
override fun onFragmentCreated(
fm: FragmentManager,
fragment: Fragment,
savedInstanceState: Bundle?
) {
// 检测 Activity 中的 ViewModel。
ViewModelClearedWatcher.install(fragment, reachabilityWatcher)
}
override fun onFragmentViewDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
val view = fragment.view
if (view != null) {
// 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
) {
//ObjectWatcher 检测
reachabilityWatcher.expectWeaklyReachable(
fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
)
}
同比activity的监控差不多是一样的逻辑。
而AndroidXFragmentDestroyWatcher
是多了ViewModelClearedWatcher
的监听的,如下:
internal class ViewModelClearedWatcher(
storeOwner: ViewModelStoreOwner,
private val reachabilityWatcher: ReachabilityWatcher
) : ViewModel() {
private val viewModelMap: Map<String, ViewModel>?
init {
//通过反射,拿到ViewModel的集合
viewModelMap = try {
val mMapField = ViewModelStore::class.java.getDeclaredField("mMap")
mMapField.isAccessible = true
@Suppress("UNCHECKED_CAST")
mMapField[storeOwner.viewModelStore] as Map<String, ViewModel>
} catch (ignored: Exception) {
null
}
}
//当不再使用此ViewModel并将其销毁时,将调用此方法
override fun onCleared() {
viewModelMap?.values?.forEach { viewModel ->
//清除的时候会加入 检测
reachabilityWatcher.expectWeaklyReachable(
viewModel, "${viewModel::class.java.name} received ViewModel#onCleared() callback"
)
}
}
companion object {
fun install(
storeOwner: ViewModelStoreOwner,
reachabilityWatcher: ReachabilityWatcher
) {
val provider = ViewModelProvider(storeOwner, object : Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T =
//创建ViewModelClearedWatcher 实例
ViewModelClearedWatcher(storeOwner, reachabilityWatcher) as T
})
provider.get(ViewModelClearedWatcher::class.java)
}
}
}
大意就是拿到ViewModel
,并监听onCleared
方法,在回调时候去执行 reachabilityWatcher.expectWeaklyReachable
方法,逻辑也是差不多的。
RootViewWatcher
class RootViewWatcher(
private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {
override fun install() {
if (Build.VERSION.SDK_INT < 19) {
return
}
//这里相当于去拿windom管理的view,然后洗一遍,加入Runnable监听事件
swapViewManagerGlobalMViews { mViews ->
object : ArrayList<View>(mViews) {
override fun add(element: View): Boolean {
onRootViewAdded(element)
return super.add(element)
}
}
}
}
override fun uninstall() {
if (Build.VERSION.SDK_INT < 19) {
return
}
swapViewManagerGlobalMViews { mViews ->
ArrayList(mViews)
}
}
@SuppressLint("PrivateApi")
@Suppress("FunctionName")
private fun swapViewManagerGlobalMViews(swap: (ArrayList<View>) -> ArrayList<View>) {
try {
//反射去拿WindowManagerGlobal实例
val windowManagerGlobalClass = Class.forName("android.view.WindowManagerGlobal")
val windowManagerGlobalInstance =
windowManagerGlobalClass.getDeclaredMethod("getInstance").invoke(null)
val mViewsField =
windowManagerGlobalClass.getDeclaredField("mViews").apply { isAccessible = true }
@Suppress("UNCHECKED_CAST")
val mViews = mViewsField[windowManagerGlobalInstance] as ArrayList<View>
mViewsField[windowManagerGlobalInstance] = swap(mViews)
} catch (ignored: Throwable) {
SharkLog.d(ignored) { "Could not watch detached root views" }
}
}
private fun onRootViewAdded(rootView: View) {
//去监听view的attach变换,去监听。在调用onViewDetachedFromWindow是执行该方法
rootView.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
//开启一个Runnable去执行
val watchDetachedView = Runnable {
//rootView开启监听
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)
}
})
}
}
大意就是通过反射拿到window管理的mViews集合,然后遍历然后加了onViewAttachedToWindow
和onViewDetachedFromWindow
监听,在其销毁的时候执行reachabilityWatcher.expectWeaklyReachable
方法,跟上面大意是一样的,销毁时候加入监控。
ServiceWatcher
private fun onServicePreDestroy(
token: IBinder,
service: Service
) {
//根据IBinder加入map中
servicesToBeDestroyed[token] = WeakReference(service)
}
private fun onServiceDestroyed(token: IBinder) {
servicesToBeDestroyed.remove(token)?.also { serviceWeakReference ->
serviceWeakReference.get()?.let { service ->
//销毁加入监听
reachabilityWatcher.expectWeaklyReachable(
service, "${service::class.java.name} received Service#onDestroy() callback"
)
}
}
}
在调用service调用onstop的时候加入一个集合map中,在其销毁回调的时候加入监听。大意都差不多。
看完四种模型的监控方式,在看主代码ObjectWatcher
,都是通过expectWeaklyReachable
方法开始的。
@Synchronized override fun expectWeaklyReachable(
watchedObject: Any,
description: String
) {
if (!isEnabled()) {
return
}
//先看这个
removeWeaklyReachableObjects()
//生成唯一的id,存入watchedObjects中
val key = UUID.randomUUID()
.toString()
val watchUptimeMillis = clock.uptimeMillis()
//创建KeyedWeakReference 并且加入引用队列queue,很重要
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"
}
//存入map集合中
watchedObjects[key] = reference
//执行Runnable
checkRetainedExecutor.execute {
moveToRetained(key)
}
}
removeWeaklyReachableObjects()
先看这个方法:还记得前面的原理二吗?这里就是其应用。
WeakReferences会在它们指向的对象变得可达性后立即入队。这是在最终确定或垃圾回收实际发生之前。
//KeyedWeakReference集合,每次监听会生成唯一id的key加入其中
private val watchedObjects = mutableMapOf<String, KeyedWeakReference>()
//引用队列,被回收了会加入其队列
private val queue = ReferenceQueue<Any>()
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) {
//不为空,说明该对象已经被gc回收了,不需要在监听了,属于正常销毁回收。
watchedObjects.remove(ref.key)
}
//然后继续清理下一个,为null说明没有被gc回收
} while (ref != null)
}
checkRetainedExecutor初始化
retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
checkRetainedExecutor = {
check(isInstalled) {
"AppWatcher not installed"
}
mainHandler.postDelayed(it, retainedDelayMillis)
},
初始化设置了间隔时间为5s,有足够的时间触发gc,所以后面还会执行removeWeaklyReachableObjects
操作。
moveToRetained(key)
@Synchronized private fun moveToRetained(key: String) {
//在检测一篇
removeWeaklyReachableObjects()
//根据key取出被检测对象的KeyedWeakReference
val retainedRef = watchedObjects[key]
if (retainedRef != null) {
//不为null就是泄露了
retainedRef.retainedUptimeMillis = clock.uptimeMillis()
//这里会执行InternalLeakCanary里面实现OnObjectRetainedListener的回调方法
onObjectRetainedListeners.forEach { it.onObjectRetained() }
}
}
scheduleRetainedObjectCheck
fun scheduleRetainedObjectCheck() {
if (this::heapDumpTrigger.isInitialized) {
heapDumpTrigger.scheduleRetainedObjectCheck()
}
}
fun scheduleRetainedObjectCheck(
delayMillis: Long = 0L
) {
val checkCurrentlyScheduledAt = checkScheduledAt
if (checkCurrentlyScheduledAt > 0) {
//操作中返回
return
}
checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
backgroundHandler.postDelayed({
checkScheduledAt = 0
checkRetainedObjects()
}, delayMillis)
}
最终会走checkRetainedObjects方法
checkRetainedObjects
private fun checkRetainedObjects() {
val iCanHasHeap = HeapDumpControl.iCanHasHeap()
...
...
val config = configProvider()
//获取被监测的数量
var retainedReferenceCount = objectWatcher.retainedObjectCount
if (retainedReferenceCount > 0) {
//大于0,手动触发gc
gcTrigger.runGc()
retainedReferenceCount = objectWatcher.retainedObjectCount
}
//这里会做一大堆是否要进行堆转储的判断
if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return
//返回false继续
val now = SystemClock.uptimeMillis()
//获取上次堆转储的时间差
val elapsedSinceLastDumpMillis = now - lastHeapDumpUptimeMillis
//小于1分钟间隔,不会再操作。堆转储是消耗性能的操作
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"
)
}
dumpHeap
private fun dumpHeap(
retainedReferenceCount: Int,
retry: Boolean,
reason: String
) {
//保存资源id到内存
saveResourceIdNamesToMemory()
//记录时间
val heapDumpUptimeMillis = SystemClock.uptimeMillis()
KeyedWeakReference.heapDumpUptimeMillis = heapDumpUptimeMillis
//执行操作
when (val heapDumpResult = heapDumper.dumpHeap()) {
//失败回调
is NoHeapDump -> {
if (retry) {
SharkLog.d { "Failed to dump heap, will retry in $WAIT_AFTER_DUMP_FAILED_MILLIS ms" }
scheduleRetainedObjectCheck(
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
)
)
}
//成功回调
is HeapDump -> {
lastDisplayedRetainedObjectCount = 0
//更新时间,1分钟内只会调用一次
lastHeapDumpUptimeMillis = SystemClock.uptimeMillis()
//在清理一次
objectWatcher.clearObjectsWatchedBefore(heapDumpUptimeMillis)
//HeapAnalyzerService启动service分析
HeapAnalyzerService.runAnalysis(
context = application,
heapDumpFile = heapDumpResult.file,
heapDumpDurationMillis = heapDumpResult.durationMillis,
heapDumpReason = reason
)
}
}
}
这里的heapDumper.dumpHeap()
实际调用的是AndroidHeapDumper
的dumpHeap
方法。
dumpHeap
override fun dumpHeap(): DumpHeapResult {
//获取将要转储文件位置
val heapDumpFile = leakDirectoryProvider.newHeapDumpFile() ?: return NoHeapDump
val waitingForToast = FutureResult<Toast?>()
showToast(waitingForToast)
//超时执行NoHeapDump 回调
if (!waitingForToast.wait(5, SECONDS)) {
SharkLog.d { "Did not dump heap, too much time waiting for Toast." }
return NoHeapDump
}
...
通知栏的一些操作
...
val toast = waitingForToast.get()
return try {
val durationMillis = measureDurationMillis {
//核心操作,调用原生的堆转储文件
Debug.dumpHprofData(heapDumpFile.absolutePath)
}
if (heapDumpFile.length() == 0L) {
//失败,还是执行NoHeapDump回调
SharkLog.d { "Dumped heap file is 0 byte length" }
NoHeapDump
} else {
//执行成功回调
HeapDump(file = heapDumpFile, durationMillis = durationMillis)
}
} catch (e: Exception) {
SharkLog.d(e) { "Could not dump heap" }
// Abort heap dump
//转换过程坑会报io异常
NoHeapDump
} finally {
cancelToast(toast)
notificationManager.cancel(R.id.leak_canary_notification_dumping_heap)
}
}
在回到HeapAnalyzerService.runAnalysis那边进行分析操作
HeapAnalyzerService.runAnalysis
这个类继承了ForegroundService,而这个是一个IntentService类型的,会执行完自动关闭。
所以会执行onHandleIntent
方法,从而走到onHandleIntentInForeground
方法。
override fun onHandleIntentInForeground(intent: Intent?) {
if (intent == null || !intent.hasExtra(HEAPDUMP_FILE_EXTRA)) {
SharkLog.d { "HeapAnalyzerService received a null or empty intent, ignoring." }
return
}
// Since we're running in the main process we should be careful not to impact it.
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)
val heapDumpFile = intent.getSerializableExtra(HEAPDUMP_FILE_EXTRA) as File
val heapDumpReason = intent.getStringExtra(HEAPDUMP_REASON_EXTRA)
val heapDumpDurationMillis = intent.getLongExtra(HEAPDUMP_DURATION_MILLIS_EXTRA, -1)
val config = LeakCanary.config
val heapAnalysis = if (heapDumpFile.exists()) {
analyzeHeap(heapDumpFile, config)
} else {
missingFileFailure(heapDumpFile)
}
val fullHeapAnalysis = when (heapAnalysis) {
is HeapAnalysisSuccess -> heapAnalysis.copy(
dumpDurationMillis = heapDumpDurationMillis,
metadata = heapAnalysis.metadata + ("Heap dump reason" to heapDumpReason)
)
is HeapAnalysisFailure -> heapAnalysis.copy(dumpDurationMillis = heapDumpDurationMillis)
}
onAnalysisProgress(REPORTING_HEAP_ANALYSIS)
config.onHeapAnalyzedListener.onHeapAnalyzed(fullHeapAnalysis)
}
会调用analyzeHeap
方法,HeapAnalyzer
是用于分析堆内存的,再走到heapAnalyzer.analyze
方法里面
heapAnalyzer.analyze
fun analyze(
heapDumpFile: File,
leakingObjectFinder: LeakingObjectFinder,
referenceMatchers: List<ReferenceMatcher> = emptyList(),
computeRetainedHeapSize: Boolean = false,
objectInspectors: List<ObjectInspector> = emptyList(),
metadataExtractor: MetadataExtractor = MetadataExtractor.NO_OP,
proguardMapping: ProguardMapping? = null
): HeapAnalysis {
val analysisStartNanoTime = System.nanoTime()
...
...
return try {
//监听状态回调
listener.onAnalysisProgress(PARSING_HEAP_DUMP)
//打开io操作
val sourceProvider = ConstantMemoryMetricsDualSourceProvider(FileSourceProvider(heapDumpFile))
//打开堆栈图
sourceProvider.openHeapGraph(proguardMapping).use { graph ->
//创建FindLeakInput
val helpers =
FindLeakInput(graph, referenceMatchers, computeRetainedHeapSize, objectInspectors)
//调用analyzeGraph分析
val result = helpers.analyzeGraph(
metadataExtractor, leakingObjectFinder, heapDumpFile, analysisStartNanoTime
)
val lruCacheStats = (graph as HprofHeapGraph).lruCacheStats()
val randomAccessStats =
"RandomAccess[" +
"bytes=${sourceProvider.randomAccessByteReads}," +
"reads=${sourceProvider.randomAccessReadCount}," +
"travel=${sourceProvider.randomAccessByteTravel}," +
"range=${sourceProvider.byteTravelRange}," +
"size=${heapDumpFile.length()}" +
"]"
val stats = "$lruCacheStats $randomAccessStats"
result.copy(metadata = result.metadata + ("Stats" to stats))
}
} catch (exception: Throwable) {
...
...
)
}
}
private fun FindLeakInput.analyzeGraph(
metadataExtractor: MetadataExtractor,
leakingObjectFinder: LeakingObjectFinder,
heapDumpFile: File,
analysisStartNanoTime: Long
): HeapAnalysisSuccess {
//监听回调
listener.onAnalysisProgress(EXTRACTING_METADATA)
//提前元数据
val metadata = metadataExtractor.extractMetadata(graph)
//最后检测一遍引用计数
val retainedClearedWeakRefCount = KeyedWeakReferenceFinder.findKeyedWeakReferences(graph)
.filter { it.isRetained && !it.hasReferent }.count()
// This should rarely happens, as we generally remove all cleared weak refs right before a heap
// dump.
val metadataWithCount = if (retainedClearedWeakRefCount > 0) {
metadata + ("Count of retained yet cleared" to "$retainedClearedWeakRefCount KeyedWeakReference instances")
} else {
metadata
}
listener.onAnalysisProgress(FINDING_RETAINED_OBJECTS)
//通过泄露堆图找到一组泄露对象id
val leakingObjectIds = leakingObjectFinder.findLeakingObjectIds(graph)
//再通过id找到gcroot的路径,找到不可达的对象,由于存在多条泄露对象的路径,要多次记录分析
val (applicationLeaks, libraryLeaks, unreachableObjects) = findLeaks(leakingObjectIds)
return HeapAnalysisSuccess(
heapDumpFile = heapDumpFile,
createdAtTimeMillis = System.currentTimeMillis(),
analysisDurationMillis = since(analysisStartNanoTime),
metadata = metadataWithCount,
applicationLeaks = applicationLeaks,
libraryLeaks = libraryLeaks,
unreachableObjects = unreachableObjects
)
}
大意就是通过 IntentService 服务来分析 hprof 文件,分析库使用的是 Shark。具体步骤是首选生成 heap graph(对象关系图),在通过我们放入的弱引用对象来确定泄露的对象,再遍历对象关联的路径生成最短路径。