Reputation:
I am getting a memory leak notification via leak canary where it says my fragment instance leaks due to references held from eventlisteners and Arraylist.array. Not sure how to fix this, any ideas?
@Override
ArrayList<myInterface> getnewList() {
ArrayList<myInterface> inst = new ArrayList<>();
inst.addAll(myRepository.getList());
inst.addAll(myRepository.getOtherList());
Collections.sort(inst, myRepository.myComparator);
return inst;
}
Here's the leak trace which gives an indication of the leak:
In com.myproject.project2.alpha.debug:3.0.0:3000000.
* com.project.newzy.dashboard.myListFragment has leaked:
* GC ROOT static com.myproject.repository.myRepository.eventListeners
* references java.util.ArrayList.array
* references array java.lang.Object[].[0]
* leaks com.project.newzy.dashboard.myListFragment instance
* Retaining: 251 KB.
* Reference Key: cc806908-52f6-42f5-be98-b39665dfa218
* Device: samsung samsung SM-J327P j3popltespr
* Android Version: 6.0.1 API: 23 LeakCanary: 1.5.1 1be44b3
* Durations: watch=5463ms, gc=131ms, heap dump=3776ms, analysis=40370ms
* Details:
* Class com.myproject.repository.myRepository
| static eventListeners = java.util.ArrayList@587750272 (0x23085b80)
| static Comparator = com.myproject.repository.myRepository$5@587741136 (0x230837d0)
| static $staticOverhead = byte[40]@584327169 (0x22d42001)
| static initialized = true
| static lock = java.lang.Object@587741152 (0x230837e0)
| static cache = java.util.concurrent.ConcurrentHashMap@587732480 (0x23081600)
* Instance of java.util.ArrayList
| static $staticOverhead = byte[16]@1893860329 (0x70e203e9)
| static MIN_CAPACITY_INCREMENT = 12
| static serialVersionUID = 8683452581122892189
| array = java.lang.Object[12]@591375616 (0x233fad00)
| size = 1
| modCount = 1
| shadow$_klass_ = java.util.ArrayList
| shadow$_monitor_ = 0
* Array of java.lang.Object[]
| [0] = com.project.newzy.dashboard.myListFragment@596231392 (0x2389c4e0)
| [1] = null
| [2] = null
| [3] = null
| [4] = null
| [5] = null
| [6] = null
| [7] = null
| [8] = null
| [9] = null
| [10] = null
| [11] = null
* Instance of com.project.newzy.dashboard.myListFragment
| static $staticOverhead = byte[16]@583464961 (0x22c6f801)
| static serialVersionUID = 0
| static $change = null
| adapter = com.project.newzy.dashboard.DashboardAdapter@590877408 (0x233812e0)
| myRepository = com.myproject.repository.myRepository@587661072 (0x2306ff10)
| inst = java.util.ArrayList@591400160 (0x23400ce0)
| emptyLayout = android.widget.RelativeLayout@593542144 (0x2360bc00)
| emptyMessage = android.support.v7.widget.AppCompatTextView@593544192 (0x2360c400)
| floatingActionButton = android.support.design.widget.FloatingActionButton@594071552 (0x2368d000)
| roomList = com.project.gui.advancedrecyclerview.AdvancedRecyclerView@593541120 (0x2360b800)
| selectedVGroupID = null
| listAdapter = com.project.newzy.dashboard.DashboardAdapter@590877408 (0x233812e0)
| listDivider = com.project.newzy.base.helpers.DividerItemDecoration@589723120 (0x232675f0)
| listManager = android.support.v7.widget.LinearLayoutManager@591052128 (0x233abd60)
| listView = com.project.gui.advancedrecyclerview.AdvancedRecyclerView@593541120 (0x2360b800)
| mAdded = true
| mAnimationInfo = null
| mArguments = null
| mBackStackNesting = 0
| mCalled = true
| mCheckedForLoaderManager = true
| mChildFragmentManager = android.support.v4.app.FragmentManagerImpl@588818688 (0x2318a900)
| mChildNonConfig = null
| mContainer = android.support.v4.view.ViewPager@597927936 (0x23a3a800)
| mContainerId = 2131755178
| mDeferStart = false
| mDetached = false
| mFragmentId = 2131755178
| mFragmentManager = android.support.v4.app.FragmentManagerImpl@598589728 (0x23adc120)
| mFromLayout = false
| mHasMenu = false
| mHidden = false
| mHiddenChanged = false
| mHost = android.support.v4.app.FragmentActivity$HostCallbacks@598610224 (0x23ae1130)
| mInLayout = false
| mIndex = 1
| mInnerView = android.widget.RelativeLayout@593536000 (0x2360a400)
| mIsNewlyAdded = false
| mLoaderManager = null
| mLoadersStarted = true
| mMenuVisible = true
| mParentFragment = null
| mPostponedAlpha = 0.0
| mRemoving = false
| mRestored = false
| mRetainInstance = false
| mRetaining = false
| mSavedFragmentState = null
| mSavedViewState = null
| mState = 5
| mTag = java.lang.String@590080848 (0x232beb50)
| mTarget = null
| mTargetIndex = -1
| mTargetRequestCode = 0
| mUserVisibleHint = true
| mView = android.widget.RelativeLayout@593536000 (0x2360a400)
| mWho = java.lang.String@591143744 (0x233c2340)
| shadow$_klass_ = com.project.newzy.dashboard.myListFragment
| shadow$_monitor_ = -2032154546
* Excluded Refs:
| Field: android.view.inputmethod.InputMethodManager.mNextServedView
| Field: android.view.inputmethod.InputMethodManager.mServedView
| Field: android.view.inputmethod.InputMethodManager.mServedInputConnection
| Field: android.view.inputmethod.InputMethodManager.mCurRootView
| Field: android.os.UserManager.mContext
| Field: android.net.ConnectivityManager.sInstance
| Field: android.view.Choreographer$FrameDisplayEventReceiver.mMessageQueue (always)
| Thread:FinalizerWatchdogDaemon (always)
| Thread:main (always)
| Thread:LeakCanary-Heap-Dump (always)
| Class:java.lang.ref.WeakReference (always)
| Class:java.lang.ref.SoftReference (always)
| Class:java.lang.ref.PhantomReference (always)
| Class:java.lang.ref.Finalizer (always)
| Class:java.lang.ref.FinalizerReference (always)
Please let me know if you guys have faced this before and have any clues about how to go about fixing it?
Upvotes: 2
Views: 1620
Reputation: 455
It seems that your myRepository
class holds a reference to a Fragment instance myListFragment
.
I do not know the implementation of myRepository
but if I can make a guess, this class is probably a Singleton class so it resides in memory for the whole application process. Fragment and Activity context is a big memory chunk and since a Singleton class holds a reference to that memory, Garbage Collector cannot clear that Fragment/Activity memory when it finishes its lifecycle which means your Fragment instance will also reside in memory throughout the whole application lifecycle. One blog about meomory leak: https://android.jlelse.eu/memory-leak-patterns-in-android-4741a7fcb570
I can recommend one fix to your problem:
Hope this helps.
Upvotes: 0
Reputation: 13272
The stack trace shows that the com.myproject.repository.myRepository
is holding a reference to com.project.newzy.dashboard.myListFragment
in the eventListeners
array.
I'm not sure exactly what your myRepository
is but (probably it used as an Observable
) it's holding a reference to an myListFragment
(probably a Fragment
) that the UI
needs to destroy.
To solve the issue you need to ensure that when the myListFragment
is about to be destroyed it's no longer part of the eventListeners
array. Just remove the listener from the array in onPause
and register it back in onResume
.
Upvotes: 1