源码基于 com.squareup.leakcanary:leakcanary-android:2.7
。
LeakCanary 初始化
LeakCanary 通过 ContentProvider 完成自动初始化。
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.squareup.leakcanary.objectwatcher">
<application>
<provider
android:name="leakcanary.internal.AppWatcherInstaller$MainProcess"
android:authorities="${applicationId}.leakcanary-installer"
android:enabled="@bool/leak_canary_watcher_auto_install"
android:exported="false"/>
</application>
</manifest>
internal sealed class AppWatcherInstaller : ContentProvider() {
internal class MainProcess : AppWatcherInstaller()
internal class LeakCanaryProcess : AppWatcherInstaller()
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
AppWatcher.manualInstall(application)
return true
}
}
object AppWatcher {
fun manualInstall(
application: Application,
retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)) {
checkMainThread()
LeakCanaryDelegate.loadLeakCanary(application)
watchersToInstall.forEach {
it.install()
}
}
fun appDefaultWatchers(...): List<InstallableWatcher> {
return listOf(
ActivityWatcher(application, reachabilityWatcher),
FragmentAndViewModelWatcher(application, reachabilityWatcher),
RootViewWatcher(reachabilityWatcher),
ServiceWatcher(reachabilityWatcher)
)
}
}
internal object LeakCanaryDelegate {
// 因为 InternalLeakCanary 类是上层模块的,这里没有办法直接引用
val loadLeakCanary by lazy {
val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary")
leakCanaryListener.getDeclaredField("INSTANCE")
.get(null) as (Application) -> Unit
}
}
internal object InternalLeakCanary : (Application) -> Unit, OnObjectRetainedListener {
override fun invoke(application: Application) {
// 内存泄漏时回调该类的方法
AppWatcher.objectWatcher.addOnObjectRetainedListener(this)
val heapDumper = AndroidHeapDumper(application, createLeakDirectoryProvider(application))
heapDumpTrigger = HeapDumpTrigger(
application, backgroundHandler, AppWatcher.objectWatcher, gcTrigger, heapDumper, configProvider)
// 动态添加Shortcut
addDynamicShortcut(application)
}
}
InternalLeakCanary 的部分声明为 object InternalLeakCanary : (Application) -> Unit,对应 kotlin 中 Functions.kt 文件的 Function1 接口,P1 为 Application,R 为 Unit 即 void:
/** A function that takes 1 argument. */
public interface Function1<in P1, out R> : Function<R> {
/** Invokes the function with the specified argument. */
public operator fun invoke(p1: P1): R
}
观察对象
观察 Activity 对象
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)
}
}
通过 Application.ActivityLifecycleCallbacks#onActivityDestroyed() 监听 Activity 对象。
观察 Fragment 对象
class FragmentAndViewModelWatcher(
private val application: Application,
private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {
private val fragmentDestroyWatchers: List<(Activity) -> Unit> = run {
val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()
// AndroidOFragmentDestroyWatcher 观察 android.app.Fragment
if (SDK_INT >= O) {
fragmentDestroyWatchers.add(AndroidOFragmentDestroyWatcher(reachabilityWatcher))
}
// AndroidXFragmentDestroyWatcher 观察 androidx.fragment.app.Fragment
getWatcherIfAvailable(
ANDROIDX_FRAGMENT_CLASS_NAME,
ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
reachabilityWatcher
)?.let {
fragmentDestroyWatchers.add(it)
}
// AndroidSupportFragmentDestroyWatcher 观察 android.support.v4.app.Fragment
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() {
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
override fun uninstall() {
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
}
}
通过 FragmentLifecycleCallbacks#onFragmentViewDestroyed() 和 onFragmentDestroyed() 监听 View 和 Fragment 对象。
观察 RootView 对象
class RootViewWatcher(
private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {
private val listener = OnRootViewAddedListener { rootView ->
val trackDetached = when(rootView.windowType) {
PHONE_WINDOW -> {
when (rootView.phoneWindow?.callback?.wrappedCallback) {
// Activities are already tracked by ActivityWatcher
is Activity -> false
is Dialog -> rootView.resources.getBoolean(R.bool.leak_canary_watcher_watch_dismissed_dialogs)
// Probably a DreamService
else -> true
}
}
// Android widgets keep detached popup window instances around.
POPUP_WINDOW -> false
TOOLTIP, TOAST, UNKNOWN -> true
}
if (trackDetached) {
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)
}
})
}
}
override fun install() {
Curtains.onRootViewsChangedListeners += listener
}
override fun uninstall() {
Curtains.onRootViewsChangedListeners -= listener
}
}
通过 View.OnAttachStateChangeListener#onViewDetachedFromWindow() 监听 View 对象。
观察 Service 对象
通过 hook ActivityThread 的 H 类和 AMS,当 AMS 调用 serviceDoneExecuting 方法可做内存泄漏的检查工作。
class ServiceWatcher(private val reachabilityWatcher: ReachabilityWatcher) : InstallableWatcher {
override fun install() {
// hook ActivityThread 中 H 类的 Callback
swapActivityThreadHandlerCallback { mCallback ->
Handler.Callback { msg ->
if (msg.what == STOP_SERVICE) {
val key = msg.obj as IBinder
activityThreadServices[key]?.let {
onServicePreDestroy(key, it)
}
}
mCallback?.handleMessage(msg) ?: false
}
}
// hook AMS
swapActivityManager { activityManagerInterface, activityManagerInstance ->
Proxy.newProxyInstance(
activityManagerInterface.classLoader, arrayOf(activityManagerInterface)
) { _, method, args ->
if (METHOD_SERVICE_DONE_EXECUTING == method.name) {
val token = args!![0] as IBinder
if (servicesToBeDestroyed.containsKey(token)) {
onServiceDestroyed(token)
}
}
}
}
}
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"
)
}
}
}
}
通过动态代理,在调用 serviceDoneExecuting 方法时判断 Service 对象是否泄漏。
检测泄漏对象
class ObjectWatcher {
private val watchedObjects = mutableMapOf<String, KeyedWeakReference>()
private val queue = ReferenceQueue<Any>()
@Synchronized override fun expectWeaklyReachable(watchedObject: Any, description: String) {
removeWeaklyReachableObjects()
val reference = KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
watchedObjects[key] = reference
// 主线程5秒之后执行moveToRetained(key)方法
checkRetainedExecutor.execute {
moveToRetained(key)
}
}
@Synchronized private fun moveToRetained(key: String) {
removeWeaklyReachableObjects()
val retainedRef = watchedObjects[key]
if (retainedRef != null) {
retainedRef.retainedUptimeMillis = clock.uptimeMillis()
// InternalLeakCanary 实现了 OnObjectRetainedListener
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)
}
}
- 先移除队列中没有泄漏的对象;
- 把观察对象包装成 KeyedWeakReference 保存到引用队列中;
- 5s 后弱引用依然存在,可能存在内存泄漏,检测该对象。
internal object InternalLeakCanary : (Application) -> Unit, OnObjectRetainedListener {
override fun onObjectRetained() = scheduleRetainedObjectCheck()
fun scheduleRetainedObjectCheck() {
if (this::heapDumpTrigger.isInitialized) {
heapDumpTrigger.scheduleRetainedObjectCheck()
}
}
}
internal class HeapDumpTrigger(...) {
fun scheduleRetainedObjectCheck(delayMillis: Long = 0L) {
backgroundHandler.postDelayed({
checkScheduledAt = 0
checkRetainedObjects()
}, delayMillis)
}
private fun checkRetainedObjects() {
if (iCanHasHeap is Nope) {
// 判断是否可以 dump 或通知
return
}
var retainedReferenceCount = objectWatcher.retainedObjectCount
if (retainedReferenceCount > 0) {
gcTrigger.runGc()
retainedReferenceCount = objectWatcher.retainedObjectCount
}
// 泄漏对象不超过 5 个,返回
if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return
// dump 间隔小于 60s,显示通知,重新调度
if (elapsedSinceLastDumpMillis < WAIT_BETWEEN_HEAP_DUMPS_MILLIS) {
showRetainedCountNotification()
scheduleRetainedObjectCheck()
return
}
dismissRetainedCountNotification()
dumpHeap(...)
}
private fun dumpHeap(retainedReferenceCount: Int, retry: Boolean, reason: String) {
saveResourceIdNamesToMemory()
when (val heapDumpResult = heapDumper.dumpHeap()) {
is NoHeapDump -> {
showRetainedCountNotification(...)
}
is HeapDump -> {
HeapAnalyzerService.runAnalysis(...)
}
}
}
}
- GC 后判断引用的对象数量;
- 泄漏对象 >= 5 时才显示通知,启动 HeapAnalyzerService 服务,dump 内存。
dump 对象和分析 Hprof
internal class HeapAnalyzerService : ForegroundService(...), OnAnalysisProgressListener {
override fun onHandleIntentInForeground(intent: Intent?) {
val heapAnalysis = if (heapDumpFile.exists()) {
analyzeHeap(heapDumpFile, config)
} else {
missingFileFailure(heapDumpFile)
}
onAnalysisProgress(REPORTING_HEAP_ANALYSIS)
config.onHeapAnalyzedListener.onHeapAnalyzed(fullHeapAnalysis)
}
private fun analyzeHeap(heapDumpFile: File, config: Config): HeapAnalysis {
val heapAnalyzer = HeapAnalyzer(this)
return heapAnalyzer.analyze()
}
}
class HeapAnalyzer constructor(private val listener: OnAnalysisProgressListener) {
fun analyze(...){
listener.onAnalysisProgress(PARSING_HEAP_DUMP)
val sourceProvider = ConstantMemoryMetricsDualSourceProvider(FileSourceProvider(heapDumpFile))
sourceProvider.openHeapGraph(proguardMapping).use {
val helpers = FindLeakInput(graph, ...)
val result = helpers.analyzeGraph(metadataExtractor, ...)
}
}
}
总结
LeakCanary 检测流程- 通过 ContentProvider 初始化 LeakCanary;
- 在 Activity、Fragment、RootView 和 Service 对象的“终结”生命周期中观察对象;
- 生成 uuid,把观察的对象包装成弱引用,添加到引用队列;
- 如果泄漏对象 > 0,触发 GC,GC 后泄漏对象 >= 5 时,显示通知,dump 内存;
- 通过 shark 库分析 hprof 文件,查找泄露对象引用路径,存储分析结果。
网友评论