androidbroadcast / ViewBindingPropertyDelegate

Make work with Android View Binding simpler
https://proandroiddev.com/make-android-view-binding-great-with-kotlin-b71dd9c87719
Apache License 2.0
1.42k stars 102 forks source link

Memory leaks (according to LeakCanary) #80

Closed cristan closed 2 years ago

cristan commented 2 years ago

Steps to reproduce

I have tested this on versions 1.5.0-beta01 and 1.4.7.

Test project: LeakCanarytest.zip

LeakCanary report

┬───
│ GC Root: Local variable in native code
│
├─ android.os.HandlerThread instance
│    Leaking: NO (PathClassLoader↓ is not leaking)
│    Thread name: 'LeakCanary-Heap-Dump'
│    ↓ Thread.contextClassLoader
├─ dalvik.system.PathClassLoader instance
│    Leaking: NO (InternalLeakCanary↓ is not leaking and A ClassLoader is never
│    leaking)
│    ↓ ClassLoader.runtimeInternalObjects
├─ java.lang.Object[] array
│    Leaking: NO (InternalLeakCanary↓ is not leaking)
│    ↓ Object[].[345]
├─ leakcanary.internal.InternalLeakCanary class
│    Leaking: NO (ItemDetailHostActivity↓ is not leaking and a class is never
│    leaking)
│    ↓ static InternalLeakCanary.resumedActivity
├─ com.test.leakcanarytest.ItemDetailHostActivity instance
│    Leaking: NO (NavHostFragment↓ is not leaking and Activity#mDestroyed is
│    false)
│    mApplication instance of android.app.Application
│    mBase instance of androidx.appcompat.view.ContextThemeWrapper
│    ↓ FragmentActivity.mFragments
├─ androidx.fragment.app.FragmentController instance
│    Leaking: NO (NavHostFragment↓ is not leaking)
│    ↓ FragmentController.mHost
├─ androidx.fragment.app.FragmentActivity$HostCallbacks instance
│    Leaking: NO (NavHostFragment↓ is not leaking)
│    this$0 instance of com.test.leakcanarytest.ItemDetailHostActivity with
│    mDestroyed = false
│    mActivity instance of com.test.leakcanarytest.ItemDetailHostActivity with
│    mDestroyed = false
│    mContext instance of com.test.leakcanarytest.ItemDetailHostActivity with
│    mDestroyed = false
│    ↓ FragmentHostCallback.mFragmentManager
├─ androidx.fragment.app.FragmentManagerImpl instance
│    Leaking: NO (NavHostFragment↓ is not leaking)
│    ↓ FragmentManager.mPrimaryNav
├─ androidx.navigation.fragment.NavHostFragment instance
│    Leaking: NO (Fragment#mFragmentManager is not null)
│    ↓ Fragment.mChildFragmentManager
│               ~~~~~~~~~~~~~~~~~~~~~
├─ androidx.fragment.app.FragmentManagerImpl instance
│    Leaking: UNKNOWN
│    Retaining 343,5 kB in 6974 objects
│    ↓ FragmentManager.mLifecycleCallbacksDispatcher
│                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
├─ androidx.fragment.app.FragmentLifecycleCallbacksDispatcher instance
│    Leaking: UNKNOWN
│    Retaining 342,3 kB in 6930 objects
│    ↓ FragmentLifecycleCallbacksDispatcher.mLifecycleCallbacks
│                                           ~~~~~~~~~~~~~~~~~~~
├─ java.util.concurrent.CopyOnWriteArrayList instance
│    Leaking: UNKNOWN
│    Retaining 342,3 kB in 6929 objects
│    ↓ CopyOnWriteArrayList.array
│                           ~~~~~
├─ java.lang.Object[] array
│    Leaking: UNKNOWN
│    Retaining 342,3 kB in 6927 objects
│    ↓ Object[].[4]
│               ~~~
├─ androidx.fragment.app.
│  FragmentLifecycleCallbacksDispatcher$FragmentLifecycleCallbacksHolder
│  instance
│    Leaking: UNKNOWN
│    Retaining 69,1 kB in 1417 objects
│    ↓ FragmentLifecycleCallbacksDispatcher$FragmentLifecycleCallbacksHolder.
│    mCallback
│    ~~~~~~~~~
├─ by.kirich1409.viewbindingdelegate.FragmentViewBindingProperty$ClearOnDestroy
│  instance
│    Leaking: UNKNOWN
│    Retaining 69,1 kB in 1416 objects
│    ↓ FragmentViewBindingProperty$ClearOnDestroy.this$0
│                                                 ~~~~~~
├─ by.kirich1409.viewbindingdelegate.FragmentViewBindingProperty instance
│    Leaking: UNKNOWN
│    Retaining 69,1 kB in 1415 objects
│    ↓ LifecycleViewBindingProperty.viewBinder
│                                   ~~~~~~~~~~
├─ by.kirich1409.viewbindingdelegate.
│  ReflectionFragmentViewBindings$viewBinding$3 instance
│    Leaking: UNKNOWN
│    Retaining 69,1 kB in 1414 objects
│    Anonymous subclass of kotlin.jvm.internal.Lambda
│    ↓ ReflectionFragmentViewBindings$viewBinding$3.$this_viewBinding
│                                                   ~~~~~~~~~~~~~~~~~
╰→ com.test.leakcanarytest.ItemDetailFragment instance
​     Leaking: YES (ObjectWatcher was watching this because com.test.
​     leakcanarytest.ItemDetailFragment received Fragment#onDestroy() callback
​     and Fragment#mFragmentManager is null)
​     Retaining 69,1 kB in 1413 objects
​     key = 5d52b4c8-0b46-472b-b34a-e3a5aa3eadbe
​     watchDurationMillis = 13054
​     retainedDurationMillis = 8051

METADATA

Build.VERSION.SDK_INT: 30
Build.MANUFACTURER: OnePlus
LeakCanary version: 2.7
App process name: com.test.leakcanarytest
Stats: LruCache[maxSize=3000,hits=3781,misses=72790,hitRate=4%]
RandomAccess[bytes=3599038,reads=72790,travel=33132802478,range=22078117,size=28
223077]
Heap dump reason: user request
Analysis duration: 2954 ms 
maklaymiklyxa commented 2 years ago

same for me, checked that 1.4.6 works ok, but upper verions provide memory leaks to fragment

kirich1409 commented 2 years ago

Hi. Thanks for the issue. I know where is the leak. Will be fixed soon