1

I was working on some issues related to memory leaks. When I was removing a fragment using a fragment transaction(fragmentManager.beginTransaction().remove(fragment).commit()), I noticed memory leaks. But when I use a pop back stack (fragmentManager.popBackStack()) I didn't saw any memory leak. This scenario made me curious to find which way is better to remove a fragment. Using Fragment Transaction or using a pop back stack.

EDIT 1 I am adding a fragment dynamically.

    fun AppCompatActivity.addFragment(fragment: Fragment, frameId: Int, tag: String) {
    supportFragmentManager.inTransaction {
        setPrimaryNavigationFragment(fragment)
        addToBackStack(tag)
        add(frameId, fragment, tag)
    }
}

EDIT 2 Memory leak output

┬───
│ GC Root: Local variable in native code
│
├─ com.esri.arcgisruntime.mapping.view.GeoView$RenderingThread instance
│    Leaking: NO (MapView↓ is not leaking)
│    Thread name: 'Rendering thread'
│    ↓ GeoView$RenderingThread.mGeoView
├─ com.esri.arcgisruntime.mapping.view.MapView instance
│    Leaking: NO (MainActivity↓ is not leaking and View attached)
│    mContext instance of main.MainActivity with mDestroyed = false
│    View.parent android.widget.LinearLayout attached as well
│    View#mParent is set
│    View#mAttachInfo is not null (view attached)
│    View.mID = R.id.mapView
│    View.mWindowAttachCount = 1
│    ↓ MapView.mContext
├─ MainActivity instance
│    Leaking: NO (SearchContainerFragment↓ is not leaking and Activity#mDestroyed is false)
│    ↓ MainActivity.navigationHandler
├─ BottomNavigationHandler instance
│    Leaking: NO (SearchContainerFragment↓ is not leaking)
│    ↓ BottomNavigationHandler.fragmentManager
├─ androidx.fragment.app.FragmentManagerImpl instance
│    Leaking: NO (SearchContainerFragment↓ is not leaking)
│    ↓ FragmentManagerImpl.mFragmentStore
├─ androidx.fragment.app.FragmentStore instance
│    Leaking: NO (SearchContainerFragment↓ is not leaking)
│    ↓ FragmentStore.mActive
├─ java.util.HashMap instance
│    Leaking: NO (SearchContainerFragment↓ is not leaking)
│    ↓ HashMap.table
├─ java.util.HashMap$Node[] array
│    Leaking: NO (SearchContainerFragment↓ is not leaking)
│    ↓ HashMap$Node[].[0]
├─ java.util.HashMap$Node instance
│    Leaking: NO (SearchContainerFragment↓ is not leaking)
│    ↓ HashMap$Node.value
├─ androidx.fragment.app.FragmentStateManager instance
│    Leaking: NO (SearchContainerFragment↓ is not leaking)
│    ↓ FragmentStateManager.mFragment
├─ SearchContainerFragment instance
│    Leaking: NO (Fragment#mFragmentManager is not null)
│    Fragment.mTag=SearchContainerFragment
│    ↓ SearchContainerFragment.adapter
│                              ~~~~~~~
├─ SearchContainerAdapter instance
│    Leaking: UNKNOWN
│    ↓ SearchContainerAdapter.mViewPagerObserver
│                             ~~~~~~~~~~~~~~~~~~
├─ androidx.viewpager.widget.ViewPager$PagerObserver instance
│    Leaking: UNKNOWN
│    ↓ ViewPager$PagerObserver.this$0
│                              ~~~~~~
├─ NonSwipeableViewPager instance
│    Leaking: YES (View detached and has parent)
│    mContext instance of MainActivity with mDestroyed = false
│    View#mParent is set
│    View#mAttachInfo is null (view detached)
│    View.mID = R.id.viewPager
│    View.mWindowAttachCount = 1
│    ↓ NonSwipeableViewPager.mParent
╰→ android.widget.RelativeLayout instance
​     Leaking: YES (ObjectWatcher was watching this because SearchContainerFragment received Fragment#onDestroyView() callback (references to its views should be cleared to prevent leaks))
​     key = 6941f63f-0f30-45b3-b62e-958477398b5b
​     watchDurationMillis = 13855
​     retainedDurationMillis = 8854
​     key = 3b8b4ecb-d3fe-4db0-b46b-2e4ab6e64bb8
​     watchDurationMillis = 13856
​     retainedDurationMillis = 8856
​     mContext instance of MainActivity with mDestroyed = false
​     View#mParent is null
​     View#mAttachInfo is null (view detached)
​     View.mWindowAttachCount = 1
METADATA
Build.VERSION.SDK_INT: 29
Build.MANUFACTURER: OnePlus
LeakCanary version: 2.2
App process name: com.dev
Analysis duration: 18920 ms```
sandeep dhami
  • 188
  • 1
  • 10
  • Can you please add a: [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve]). But one thing the answer will depend on is whether the fragment was declared statically within the XML file or if it was added to a container programmatically during runtime, but we need to see your code. Regards. – Elletlar Jun 11 '20 at 13:07
  • @Elletlar I am adding dynamically. And also edited my question. – sandeep dhami Jun 11 '20 at 13:17
  • Can you please provide the logcat output for the memory leak. – Elletlar Jun 11 '20 at 13:58
  • It looks like you are still holding a references after onDestroyView. You could try clear the references on destruction, but even better restructure the code so that the references preventing garbage collection are not necessary. – Elletlar Jun 12 '20 at 17:57
  • The references I am referring to are most likely member variables of the class not shown in your sample code above. – Elletlar Jun 12 '20 at 17:58
  • @Elletlar Yes, That is true. But I want is what popBackStack is doing that transaction remove doesn't. – sandeep dhami Jun 13 '20 at 05:55

0 Answers0