workflow-kotlin
workflow-kotlin copied to clipboard
Memory leak in Tic Tac Toe sample around HandleBackPress
trafficstars
Probably only be on the UI overhaul branch. Not sure of exact recipe. Played a full game, clicked exit. Maybe hit Back to leave the app?
====================================
0 LIBRARY LEAKS
A Library Leak is a leak caused by a known bug in 3rd party code that you do not have control over.
See https://square.github.io/leakcanary/fundamentals-how-leakcanary-works/#4-categorizing-leaks
====================================
0 UNREACHABLE OBJECTS
An unreachable object is still in memory but LeakCanary could not find a strong reference path
from GC roots.
====================================
METADATA
Please include this in bug reports and Stack Overflow questions.
Build.VERSION.SDK_INT: 29
Build.MANUFACTURER: Google
LeakCanary version: 2.8.1
App process name: com.squareup.sample.tictacworkflow
Stats: LruCache[maxSize=3000,hits=29139,misses=56715,hitRate=33%]
RandomAccess[bytes=2845319,reads=56715,travel=15186150257,range=15508691,size=19686405]
Heap dump reason: 1 retained objects, app is not visible
Analysis duration: 1138 ms
Heap dump file path: /data/user/0/com.squareup.sample.tictacworkflow/cache/leakcanary/2022-04-14_15-53-29_022.hprof
Heap dump timestamp: 1649976810902
Heap dump duration: 409 ms
====================================
Setting up flushing for Thread[HeapAnalyzer,5,main]
W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@ecc1e8f
D/EGL_emulation: eglMakeCurrent: 0x79416c1bc0: ver 3 0 (tinfo 0x79d6f2ad80)
D/EGL_emulation: eglMakeCurrent: 0x79416c1bc0: ver 3 0 (tinfo 0x79d6f2ad80)
Watching instance of leakcanary.internal.activity.LeakActivity (leakcanary.internal.activity.LeakActivity received Activity#onDestroy() callback) with key 9fef3d8a-5b01-42bd-8fb6-6954e9009722
D/EGL_emulation: eglMakeCurrent: 0x79416c1bc0: ver 3 0 (tinfo 0x79d6f2ad80)
I/.tictacworkflo: Explicit concurrent copying GC freed 19126(1209KB) AllocSpace objects, 17(340KB) LOS objects, 49% free, 3824KB/7648KB, paused 29us total 12.724ms
D/EGL_emulation: eglMakeCurrent: 0x79416c1bc0: ver 3 0 (tinfo 0x79d6f2ad80)
D/EGL_emulation: eglMakeCurrent: 0x79416c1bc0: ver 3 0 (tinfo 0x79d6f2ad80)
┬───
│ GC Root: System class
│
├─ android.view.inputmethod.InputMethodManager class
│ Leaking: NO (InputMethodManager↓ is not leaking and a class is never leaking)
│ ↓ static InputMethodManager.sInstance
├─ android.view.inputmethod.InputMethodManager instance
│ Leaking: NO (DecorView↓ is not leaking and InputMethodManager is a singleton)
│ ↓ InputMethodManager.mNextServedView
├─ com.android.internal.policy.DecorView instance
│ Leaking: NO (LinearLayout↓ is not leaking and View attached)
│ View is part of a window view hierarchy
│ View.mAttachInfo is not null (view attached)
│ View.mWindowAttachCount = 1
│ mContext instance of com.android.internal.policy.DecorContext, wrapping activity com.squareup.sample.mainactivity.
│ TicTacToeActivity with mDestroyed = false
│ ↓ DecorView.mContentRoot
├─ android.widget.LinearLayout instance
│ Leaking: NO (TicTacToeActivity↓ is not leaking and View attached)
│ View is part of a window view hierarchy
│ View.mAttachInfo is not null (view attached)
│ View.mWindowAttachCount = 1
│ mContext instance of com.squareup.sample.mainactivity.TicTacToeActivity with mDestroyed = false
│ ↓ View.mContext
├─ com.squareup.sample.mainactivity.TicTacToeActivity instance
│ Leaking: NO (Activity#mDestroyed is false)
│ mApplication instance of android.app.Application
│ mBase instance of androidx.appcompat.view.ContextThemeWrapper
│ ↓ ComponentActivity.mLifecycleRegistry
│ ~~~~~~~~~~~~~~~~~~
├─ androidx.lifecycle.LifecycleRegistry instance
│ Leaking: UNKNOWN
│ Retaining 141.3 kB in 1772 objects
│ ↓ LifecycleRegistry.mObserverMap
│ ~~~~~~~~~~~~
├─ androidx.arch.core.internal.FastSafeIterableMap instance
│ Leaking: UNKNOWN
│ Retaining 141.0 kB in 1760 objects
│ ↓ FastSafeIterableMap[key()]
│ ~~~~~~~
├─ androidx.activity.OnBackPressedDispatcher$LifecycleOnBackPressedCancellable instance
│ Leaking: UNKNOWN
│ Retaining 139.3 kB in 1691 objects
│ ↓ OnBackPressedDispatcher$LifecycleOnBackPressedCancellable.mOnBackPressedCallback
│ ~~~~~~~~~~~~~~~~~~~~~~
├─ com.squareup.workflow1.ui.HandleBackPressWhenAttached$onBackPressedCallback$1 instance
│ Leaking: UNKNOWN
│ Retaining 139.3 kB in 1689 objects
│ Anonymous subclass of androidx.activity.OnBackPressedCallback
│ ↓ HandleBackPressWhenAttached$onBackPressedCallback$1.this$0
│ ~~~~~~
├─ com.squareup.workflow1.ui.HandleBackPressWhenAttached instance
│ Leaking: UNKNOWN
│ Retaining 139.2 kB in 1685 objects
│ ↓ HandleBackPressWhenAttached.view
│ ~~~~
├─ com.squareup.workflow1.ui.container.BackStackContainer instance
│ Leaking: YES (View detached yet still part of window view hierarchy)
│ Retaining 139.2 kB in 1684 objects
│ View is part of a window view hierarchy
│ View.mAttachInfo is null (view detached)
│ View.mID = R.id.workflow_back_stack_container
│ View.mWindowAttachCount = 1
│ mContext instance of com.squareup.sample.mainactivity.TicTacToeActivity with mDestroyed = false
│ ↓ View.mParent
├─ android.widget.FrameLayout instance
│ Leaking: YES (BackStackContainer↑ is leaking and View detached yet still part of window view hierarchy)
│ Retaining 25.3 kB in 503 objects
│ View is part of a window view hierarchy
│ View.mAttachInfo is null (view detached)
│ View.mID = R.id.null
│ View.mWindowAttachCount = 1
│ mContext instance of android.view.ContextThemeWrapper, wrapping activity com.squareup.sample.mainactivity.
│ TicTacToeActivity with mDestroyed = false
│ ↓ View.mParent
├─ android.widget.LinearLayout instance
│ Leaking: YES (FrameLayout↑ is leaking and View detached yet still part of window view hierarchy)
│ Retaining 24.1 kB in 480 objects
│ View is part of a window view hierarchy
│ View.mAttachInfo is null (view detached)
│ View.mWindowAttachCount = 1
│ mContext instance of android.view.ContextThemeWrapper, wrapping activity com.squareup.sample.mainactivity.
│ TicTacToeActivity with mDestroyed = false
│ ↓ View.mParent
╰→ com.android.internal.policy.DecorView instance
Leaking: YES (ObjectWatcher was watching this because com.android.internal.policy.DecorView received
View#onDetachedFromWindow() callback)
Retaining 22.4 kB in 458 objects
key = 53dddadf-37d5-4448-927a-810b10232694
watchDurationMillis = 9265
retainedDurationMillis = 4262
View not part of a window view hierarchy
View.mAttachInfo is null (view detached)
View.mWindowAttachCount = 1
mContext instance of android.view.ContextThemeWrapper, wrapping activity com.squareup.sample.mainactivity.
TicTacToeActivity with mDestroyed = false
METADATA
Build.VERSION.SDK_INT: 29
Build.MANUFACTURER: Google
LeakCanary version: 2.8.1
App process name: com.squareup.sample.tictacworkflow
Stats: LruCache[maxSize=3000,hits=29139,misses=56715,hitRate=33%]
RandomAccess[bytes=2845319,reads=56715,travel=15186150257,range=15508691,size=19686405]
Analysis duration: 1138 ms
Damn you @pyricau
I mean looking at the code, looks like start() registers an observer to the activity lifecycle and stop() unregisters it but stop() is only called when swapping out to a new handler so there you go.