Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LeakCanary received Fragment#onDestroy() callback and Fragment#mFragmentManager is null

I am trying to fix the memory leak using the LeakCanary and honestly, I can't understand the stack trace that was showing me. I am using a firebase paging option and stop the listening on the onDestroy method. I also did not pass any activity or context to the adapter so I am sure that there is no problem in that. Below are the logs from the LeakCanary.

    HEAP ANALYSIS RESULT
    ====================================
    1 APPLICATION LEAKS
    
    References underlined with "~~~" are likely causes.
    Learn more at https://squ.re/leaks.
    
    31417285 bytes retained by leaking objects
    Signature: 31c372d2f2d3d219e828763d8f853ceca5851b
    ┬───
    β”‚ GC Root: System class
    β”‚
    β”œβ”€ leakcanary.internal.InternalLeakCanary class
    β”‚    Leaking: NO (HomeBuyersActivity↓ is not leaking and a class is never leaking)
    β”‚    ↓ static InternalLeakCanary.resumedActivity
    β”œβ”€ com.dreamakers.coonna.Activity.HomeBuyersActivity instance
    β”‚    Leaking: NO (Activity#mDestroyed is false)
    β”‚    ↓ HomeBuyersActivity.mLifecycleRegistry
    β”‚                         ~~~~~~~~~~~~~~~~~~
    β”œβ”€ androidx.lifecycle.LifecycleRegistry instance
    β”‚    Leaking: UNKNOWN
    β”‚    ↓ LifecycleRegistry.mObserverMap
    β”‚                        ~~~~~~~~~~~~
    β”œβ”€ androidx.arch.core.internal.FastSafeIterableMap instance
    β”‚    Leaking: UNKNOWN
    β”‚    ↓ FastSafeIterableMap.mEnd
    β”‚                          ~~~~
    β”œβ”€ androidx.arch.core.internal.SafeIterableMap$Entry instance
    β”‚    Leaking: UNKNOWN
    β”‚    ↓ SafeIterableMap$Entry.mKey
    β”‚                            ~~~~
    β”œβ”€ com.dreamakers.coonna.Adapter.DiscoverStoreAdapter instance
    β”‚    Leaking: UNKNOWN
    β”‚    ↓ DiscoverStoreAdapter.mParser
    β”‚                           ~~~~~~~
    β”œβ”€ com.dreamakers.coonna.Activity.HomeFragment$11 instance
    β”‚    Leaking: UNKNOWN
    β”‚    Anonymous class implementing com.firebase.ui.firestore.SnapshotParser
    β”‚    ↓ HomeFragment$11.this$0
    β”‚                      ~~~~~~
    β•°β†’ com.dreamakers.coonna.Activity.HomeFragment instance
    ​     Leaking: YES (ObjectWatcher was watching this because com.dreamakers.coonna.Activity.HomeFragment received Fragment#onDestroy() callback and Fragment#mFragmentManager is null)
    ​     key = 6e0451ae-0c0b-4de8-8993-011515e95a80
    ​     watchDurationMillis = 6238
    ​     retainedDurationMillis = 1238
    ====================================
    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
    ====================================
    METADATA
like image 796
Mr. Baks Avatar asked Aug 05 '20 07:08

Mr. Baks


People also ask

How LeakCanary works?

LeakCanary hooks into the Android lifecycle to automatically detect when activities and fragments are destroyed and should be garbage collected. These destroyed objects are passed to an ObjectWatcher , which holds weak references to them.

What is LeakCanary?

LeakCanary 🐀 LeakCanary is a memory leak detection library for Android. LeakCanary's knowledge of the internals of the Android Framework gives it a unique ability to narrow down the cause of each leak, helping developers dramatically reduce Application Not Responding freezes and OutOfMemoryError crashes.

How does memory leak happen in Android?

Memory leaks occur when an application allocates memory for an object, but then fails to release the memory when the object is no longer being used. Over time, leaked memory accumulates and results in poor app performance and even crashes.


1 Answers

The HomeFragment was destroyed and should be garbage collected, but it cannot be garbage collected because DiscoverStoreAdapter is registered as a lifecycle listener on HomeBuyersActivity and DiscoverStoreAdapter has a mParser field which is an anonymous class implementing SnapshotParser in HomeFragment.

It's hard to say without the code, but DiscoverStoreAdapter.mParser should probably be set to null when the fragment is destroyed.

like image 135
Pierre-Yves Ricau Avatar answered Nov 09 '22 07:11

Pierre-Yves Ricau