workflow-kotlin icon indicating copy to clipboard operation
workflow-kotlin copied to clipboard

Memory leak in Tic Tac Toe sample around HandleBackPress

Open rjrjr opened this issue 3 years ago • 2 comments
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

rjrjr avatar Apr 14 '22 22:04 rjrjr

Damn you @pyricau

rjrjr avatar Apr 14 '22 23:04 rjrjr

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.

pyricau avatar Apr 14 '22 23:04 pyricau