How to automatically initialize
LeakCanary can achieve automatic initialization by simply adding dependencies. LeakCanary is initialized through ContentProvider, and LeakCanary is initialized in the onCreate method of ContentProvider. And MainProcessAppWatcherInstaller is initialized in the main thread. Note: The initialization of the ContentProvider is completed before the onCreate of the Application, so the initialization method of LeakCanary is also completed before the onCreate of the Application.
internal class MainProcessAppWatcherInstaller : ContentProvider() { override fun onCreate(): Boolean { val application = context!!.applicationContext as Application (application) return true } ... ... }
How to detect memory leaks
2.1 What did LeakCanary initialize
@JvmOverloads fun manualInstall( application: Application, retainedDelayMillis: Long = (5), watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application) ) { checkMainThread() if (isInstalled) { throw IllegalStateException( "AppWatcher already installed, see exception cause for prior install call", installCause ) } check(retainedDelayMillis >= 0) { "retainedDelayMillis $retainedDelayMillis must be at least 0 ms" } installCause = RuntimeException("manualInstall() first called here") = retainedDelayMillis if () { () } // Requires to be set (application) { () } }
fun appDefaultWatchers( application: Application, reachabilityWatcher: ReachabilityWatcher = objectWatcher ): List<InstallableWatcher> { return listOf( ActivityWatcher(application, reachabilityWatcher), FragmentAndViewModelWatcher(application, reachabilityWatcher), RootViewWatcher(reachabilityWatcher), ServiceWatcher(reachabilityWatcher) ) }
In the appDefaultWatchers method, some watchers will be initialized by default. By default, we will only monitor whether objects such as Activity, Fragment, RootView, and Service will be leaked.
2.2 How LeakCanary triggers detection
Take ActivityWatcher as an example:
/** * Expects activities to become weakly reachable soon after they receive the [] * callback. */ class ActivityWatcher( private val application: Application, private val reachabilityWatcher: ReachabilityWatcher ) : InstallableWatcher { private val lifecycleCallbacks = object : by noOpDelegate() { override fun onActivityDestroyed(activity: Activity) { ( activity, "${activity::} received Activity#onDestroy() callback" ) } } override fun install() { (lifecycleCallbacks) } override fun uninstall() { (lifecycleCallbacks) } }
When it is, a memory leak detection will be triggered. Listen to life cycle changes through ActivityLifecycleCallbacks, and call the ReachabilityWatcher's expectedWeaklyReachable method in the onActivityDestroyed method.
2.3How to detect leaked objects in LeakCanary
Taking Activity as an example, it is detected through the ReachabilityWatcher's expectWeaklyReachable method.
fun interface ReachabilityWatcher { /** * Expects the provided [watchedObject] to become weakly reachable soon. If not, * [watchedObject] will be considered retained. */ fun expectWeaklyReachable( watchedObject: Any, description: String ) }
ObjectWatcher implements the ReachabilityWatcher interface.
private val watchedObjects = mutableMapOf()
private val queue = ReferenceQueue()
@Synchronized override fun expectWeaklyReachable( watchedObject: Any, description: String ) { if (!isEnabled()) { return } removeWeaklyReachableObjects() val key = () .toString() val watchUptimeMillis = () val reference = KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue) { "Watching " + (if (watchedObject is Class<*>) () else "instance of ${}") + (if (()) " ($description)" else "") + " with key $key" } watchedObjects[key] = reference { moveToRetained(key) } }
1. Build a weak reference KeyedWeakReference instance through the observed instance watchedObject. The watchedObject is associated with the ReferenceQueue. When the object is recycled, the weak reference object will be stored in the ReferenceQueue.
2. Weak reference KeyedWeakReference instance will be stored in watchedObjects (Map).
3. During the detection process, removeWeaklyReachableObjects will be called to remove the recycled object from the watchedObjects.
4. If the object is not removed in watchedObjects and it proves that it has not been recycled, moveToRetained will be called.
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 = () as KeyedWeakReference? if (ref != null) { () } } while (ref != null) }
@Synchronized private fun moveToRetained(key: String) { removeWeaklyReachableObjects() val retainedRef = watchedObjects[key] if (retainedRef != null) { = () { () } } }
2.4 WeakReference
As long as GC finds that an object has only weak references, the weak reference object will be recycled.
public class WeakReference<T> extends Reference<T> { public WeakReference(T referent) { super(referent); } public WeakReference(T referent, ReferenceQueue<? super T> q) { super(referent, q); } }
var str: Any? = Any() val quque = ReferenceQueue<Any>() val weakReference = WeakReference<Any>(str, quque) val weakReference_before_gc = () ("reference_tag", weakReference_before_gc.toString()) str = null () Handler().postDelayed( { val weakReference_after_gc = () ("reference_tag", weakReference_after_gc.toString()) }, 2000)
2022-02-27 17:43:04.181 16634-16634/ V/reference_tag: @c87946a
2022-02-27 17:43:06.182 16634-16634/ V/reference_tag: null
This is the end of this article about how to use Android LeakCanary. For more related content on Android LeakCanary, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!