woocommerce / woocommerce-android

WooCommerce Android app
https://www.woocommerce.com/mobile
GNU General Public License v2.0
276 stars 135 forks source link

Fix memory leak in `ProductListFragment` #4992

Closed wzieba closed 2 years ago

wzieba commented 2 years ago

Similar to #4991 . The case might be the same.

┬───
│ GC Root: System class
│
├─ android.net.ConnectivityManager class
│    Leaking: NO (MainActivity↓ is not leaking and a class is never leaking)
│    ↓ static ConnectivityManager.sInstance
├─ android.net.ConnectivityManager instance
│    Leaking: NO (MainActivity↓ is not leaking)
│    mContext instance of com.woocommerce.android.ui.main.MainActivity with
│    mDestroyed = false
│    ↓ ConnectivityManager.mContext
├─ com.woocommerce.android.ui.main.MainActivity instance
│    Leaking: NO (ProductListFragment↓ is not leaking and Activity#mDestroyed
│    is false)
│    mApplication instance of com.woocommerce.android.WooCommerceDebug
│    mBase instance of androidx.appcompat.view.ContextThemeWrapper, not
│    wrapping known Android context
│    ↓ MainActivity.mActivityResultRegistry
├─ androidx.activity.ComponentActivity$2 instance
│    Leaking: NO (ProductListFragment↓ is not leaking)
│    Anonymous subclass of androidx.activity.result.ActivityResultRegistry
│    this$0 instance of com.woocommerce.android.ui.main.MainActivity with
│    mDestroyed = false
│    ↓ ComponentActivity$2.mKeyToCallback
├─ java.util.HashMap instance
│    Leaking: NO (ProductListFragment↓ is not leaking)
│    ↓ HashMap.table
├─ java.util.HashMap$Node[] array
│    Leaking: NO (ProductListFragment↓ is not leaking)
│    ↓ HashMap$Node[].[8]
├─ java.util.HashMap$Node instance
│    Leaking: NO (ProductListFragment↓ is not leaking)
│    ↓ HashMap$Node.value
├─ androidx.activity.result.ActivityResultRegistry$CallbackAndContract instance
│    Leaking: NO (ProductListFragment↓ is not leaking)
│    ↓ ActivityResultRegistry$CallbackAndContract.mCallback
├─ androidx.fragment.app.FragmentManager$9 instance
│    Leaking: NO (ProductListFragment↓ is not leaking)
│    Anonymous class implementing androidx.activity.result.
│    ActivityResultCallback
│    ↓ FragmentManager$9.this$0
├─ androidx.fragment.app.FragmentManagerImpl instance
│    Leaking: NO (ProductListFragment↓ is not leaking)
│    ↓ FragmentManagerImpl.mParent
├─ com.woocommerce.android.ui.products.ProductListFragment instance
│    Leaking: NO (Fragment#mFragmentManager is not null)
│    componentContext instance of dagger.hilt.android.internal.managers.
│    ViewComponentManager$FragmentContextWrapper, wrapping activity com.
│    woocommerce.android.ui.main.MainActivity with mDestroyed = false
│    Fragment.mTag=2131363234
│    ↓ ProductListFragment.productAdapter
│                          ~~~~~~~~~~~~~~
├─ com.woocommerce.android.ui.products.ProductListAdapter instance
│    Leaking: UNKNOWN
│    Retaining 1565880 bytes in 15928 objects
│    ↓ ProductListAdapter.mObservable
│                         ~~~~~~~~~~~
├─ androidx.recyclerview.widget.RecyclerView$AdapterDataObservable instance
│    Leaking: UNKNOWN
│    Retaining 1565752 bytes in 15925 objects
│    ↓ RecyclerView$AdapterDataObservable.mObservers
│                                         ~~~~~~~~~~
├─ java.util.ArrayList instance
│    Leaking: UNKNOWN
│    Retaining 1565740 bytes in 15924 objects
│    ↓ ArrayList.elementData
│                ~~~~~~~~~~~
├─ java.lang.Object[] array
│    Leaking: UNKNOWN
│    Retaining 1565720 bytes in 15923 objects
│    ↓ Object[].[0]
│               ~~~
├─ androidx.recyclerview.widget.RecyclerView$RecyclerViewDataObserver instance
│    Leaking: UNKNOWN
│    Retaining 1565680 bytes in 15922 objects
│    ↓ RecyclerView$RecyclerViewDataObserver.this$0
│                                            ~~~~~~
├─ androidx.recyclerview.widget.RecyclerView instance
│    Leaking: UNKNOWN
│    Retaining 1565668 bytes in 15921 objects
│    View not part of a window view hierarchy
│    View.mAttachInfo is null (view detached)
│    View.mID = R.id.productsRecycler
│    View.mWindowAttachCount = 1
│    mContext instance of dagger.hilt.android.internal.managers.
│    ViewComponentManager$FragmentContextWrapper, wrapping activity com.
│    woocommerce.android.ui.main.MainActivity with mDestroyed = false
│    ↓ RecyclerView.mParent
│                   ~~~~~~~
├─ androidx.constraintlayout.widget.ConstraintLayout instance
│    Leaking: UNKNOWN
│    Retaining 6318 bytes in 141 objects
│    View not part of a window view hierarchy
│    View.mAttachInfo is null (view detached)
│    View.mWindowAttachCount = 1
│    mContext instance of dagger.hilt.android.internal.managers.
│    ViewComponentManager$FragmentContextWrapper, wrapping activity com.
│    woocommerce.android.ui.main.MainActivity with mDestroyed = false
│    ↓ ConstraintLayout.mParent
│                       ~~~~~~~
╰→ com.woocommerce.android.widgets.ScrollChildSwipeRefreshLayout instance
​     Leaking: YES (ObjectWatcher was watching this because com.woocommerce.
​     android.ui.products.ProductListFragment received Fragment#onDestroyView()
​     callback (references to its views should be cleared to prevent leaks))
​     Retaining 5015 bytes in 120 objects
​     key = ddc4062d-6ec7-49df-9d10-a38dd4aa116c
​     watchDurationMillis = 5219
​     retainedDurationMillis = 219
​     View not part of a window view hierarchy
​     View.mAttachInfo is null (view detached)
​     View.mID = R.id.productsRefreshLayout
​     View.mWindowAttachCount = 1
​     mContext instance of dagger.hilt.android.internal.managers.
​     ViewComponentManager$FragmentContextWrapper, wrapping activity com.
​     woocommerce.android.ui.main.MainActivity with mDestroyed = false
0nko commented 2 years ago

Fixed in #5268.