作为一个小Android,之前分析项过目中LeakCanary1.6.3的源码,今天在好奇心的驱使下,刷新了下maven发现,LeakCanary已经更新到2.6版本,今天对2.6的版本也进行源码的解析。
内存泄露分析原理:还是不变的-可达性分析法
:根据是否被GC Root引用确认是否是垃圾对象要被GC回收
2.6版本跟踪内存泄露的核心原理和1.6.3版本是一样的,依赖核心理论-利用weakReference中的数据在gc后是否被添加到ReferenceQueue队列中
使用上的区别
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); } }
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.6' releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:2.6.'
实现语言的区别
路径分析库的区别
haha
库shark
库,据说减少了90%内存占用,速度提升了6倍注册的区别
Application.onCreate()
方法中进行注册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文件objectWatcher.retainedObjectCount
值,确实是否需要dump文件和通知
这也是和1.6.3版本不一样的地方,旧版本是只要有泄露都会进行dump
最后dump的过程是和旧版基本是一样的,这边不做分析了。可以参考下时序图:
AppWatcherInstaller
合并到AndroidManifest中创业与投资的本质,都是追寻一种能够穿越时空,抵达未来的高效方式。 德勤管理咨...
作者 | 楚奕 来源 | 阿里技术公众号 这篇文章主要从技术视角介绍下跨平台WebCanv...
1.某女生寝室门口贴着一个告示男生与饭盒不得入内,问何解?答曰两者都会搞大女...
前言 微服务成了互联网架构的标配模式,对微服务之间的调用的流量治理和管控就尤...
基于阿里巴巴的互联网架构、大数据技术,利用混合云架构打造全新的云化电子税 务...
1.百度是个大骗子,我抄了十几年的满分作文却从未得过满分。 2.学神在刷难题,...
背景 有时候我会碰到快速搭建测试服务的需求,比如像这样: 搭建一个 HTTP Servi...
1.在报名的路上,我看见远处的学校,轰!的一声没了。希望如此。 2.男:我一直...
本文转载自微信公众号「后端Q」,作者conan。转载本文请联系后端Q公众号。 概述 ...
3月24日,腾讯发布2020年Q4及全年财报,其中金融科技及企业服务第四季收入385亿...