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) }
1.1.2 val reference =KeyedWeakReference()
KeyedWeakReference弱引用
1 2 3
A weak reference used by [ObjectWatcher] to determine which objects become weakly reachable and which don't. [ObjectWatcher] uses [key] to keep track of [KeyedWeakReference] instances that haven't made it into the associated [ReferenceQueue] yet.
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( 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) }
判断剩余引用数量 > 0 时,gcTrigger.runGc()
同1.5时,常规做法
1 2 3 4 5 6 7 8 9
override fun runGc() {
// System.gc() does not garbage collect every time. Runtime.gc() is // more likely to perform a gc. Runtime.getRuntime() .gc() enqueueReferences() System.runFinalization() }
检查剩余引用数量 checkRetainedCount()
retainedVisibleThreshold 默认是5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/** * When the app is visible, LeakCanary will wait for at least * [retainedVisibleThreshold] retained instances before dumping the heap. Dumping the heap * freezes the UI and can be frustrating for developers who are trying to work. This is * especially frustrating as the Android Framework has a number of leaks that cannot easily * be fixed. * * When the app becomes invisible, LeakCanary dumps the heap after * [AppWatcher.Config.watchDurationMillis] ms. * * The app is considered visible if it has at least one activity in started state. * * A higher threshold means LeakCanary will dump the heap less often, therefore it won't be * bothering developers as much but it could miss some leaks. * * Defaults to 5. */
internal class AndroidOFragmentDestroyWatcher( private val objectWatcher: ObjectWatcher, private val configProvider: () -> Config ) : (Activity) -> Unit { private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentViewDestroyed( fm: FragmentManager, fragment: Fragment ) { val view = fragment.view if (view != null && configProvider().watchFragmentViews) { objectWatcher.watch( 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 ) { if (configProvider().watchFragments) { objectWatcher.watch( fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback" ) } } }
fun onApplicationVisibilityChanged(applicationVisible: Boolean) { if (applicationVisible) { applicationInvisibleAt = -1L } else { applicationInvisibleAt = SystemClock.uptimeMillis() // Scheduling for after watchDuration so that any destroyed activity has time to become // watch and be part of this analysis. scheduleRetainedObjectCheck( reason = "app became invisible", rescheduling = false, delayMillis = AppWatcher.config.watchDurationMillis ) } }