2017-08-04 52 views
3

我收到一个内存泄漏通知通过泄漏金丝雀它说我的片段实例泄漏由于eventlisteners和Arraylist.array举行的引用。不知道如何解决这个问题,有什么想法?如何避免数组列表事件侦听器发生内存泄漏?

@Override 
ArrayList<myInterface> getnewList() { 
    ArrayList<myInterface> inst = new ArrayList<>(); 
    inst.addAll(myRepository.getList()); 
    inst.addAll(myRepository.getOtherList()); 
    Collections.sort(inst, myRepository.myComparator); 
    return inst; 
} 

这里的泄漏跟踪这给泄漏的指示:

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 = [email protected] (0x23085b80) 
|   static Comparator = [email protected] (0x230837d0) 
|   static $staticOverhead = byte[40]@584327169 (0x22d42001) 
|   static initialized = true 
|   static lock = [email protected] (0x230837e0) 
|   static cache = java.util.concurrent.C[email protected] (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] = [email protected] (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 = [email protected] (0x233812e0) 
|   myRepository = [email protected] (0x2306ff10) 
|   inst = [email protected] (0x23400ce0) 
|   emptyLayout = [email protected] (0x2360bc00) 
|   emptyMessage = [email protected] (0x2360c400) 
|   floatingActionButton = [email protected] (0x2368d000) 
|   roomList = [email protected]120 (0x2360b800) 
|   selectedVGroupID = null 
|   listAdapter = [email protected] (0x233812e0) 
|   listDivider = [email protected] (0x232675f0) 
|   listManager = [email protected] (0x233abd60) 
|   listView = [email protected]120 (0x2360b800) 
|   mAdded = true 
|   mAnimationInfo = null 
|   mArguments = null 
|   mBackStackNesting = 0 
|   mCalled = true 
|   mCheckedForLoaderManager = true 
|   mChildFragmentManager = [email protected] (0x2318a900) 
|   mChildNonConfig = null 
|   mContainer = [email protected] (0x23a3a800) 
|   mContainerId = 2131755178 
|   mDeferStart = false 
|   mDetached = false 
|   mFragmentId = 2131755178 
|   mFragmentManager = [email protected] (0x23adc120) 
|   mFromLayout = false 
|   mHasMenu = false 
|   mHidden = false 
|   mHiddenChanged = false 
|   mHost = [email protected] (0x23ae1130) 
|   mInLayout = false 
|   mIndex = 1 
|   mInnerView = [email protected] (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 = [email protected] (0x232beb50) 
|   mTarget = null 
|   mTargetIndex = -1 
|   mTargetRequestCode = 0 
|   mUserVisibleHint = true 
|   mView = [email protected] (0x2360a400) 
|   mWho = [email protected] (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) 

请让我知道,如果你们以前遇到这一点,有关于如何去修复它的任何线索?

+0

你能发表确切的消息吗? – Michael

+0

刚刚添加了跟踪:) –

+0

你如何使用金丝雀泄漏得到stace? @玛丽莎尼古拉斯只是好奇。 –

回答

2

堆栈跟踪显示com.myproject.repository.myRepositoryeventListeners阵列中持有对com.project.newzy.dashboard.myListFragment的引用。

我不知道你的myRepository到底是什么,但(可能它用作Observable)它保存了到myListFragment(可能是Fragment)的参考,该UI需要给毁了。

要解决此问题,您需要确保当myListFragment即将被销毁时,它不再是eventListeners阵列的一部分。只需从中的阵列中移除侦听器,并将其注册回onResume

Fragment Lifecycle

+0

我已经从名为BaseListFragment的基类中扩展myListfragment。在该基类中,我在onstart中添加了myrepository eventlistener,并在onStop上将其删除。这不够吗?我是否也应该在mylistfragment的子类中删除它?它可以在onstart和onstop上完成,还是必须在子类中进行onpause和onresume? –

+0

@MarissaNicholas不,'onStart'和'onStop'应该可以做得很好。你提到你在'onStart'中加入'eventlistener',并在'onStop'中删除?或者活动/片段?当调用activity/fragment的onStop方法时,你应该从'eventlistener'中移除activity/fragment本身。 – dan

+0

所以我有onstart和onstop都在父类“BaseListFragment”和子类“mylistfragment”。不过,我只是将myrepository的监听器添加到父类的onstart中,并将其移除到父类的上面,但到目前为止,我没有添加或删除任何onstart和onstop子类。是否有必要将它添加并在子类的开始和结束时删除它,或者在子类中创建onresume和onpause方法来执行此操作? –

0

看来你myRepository类持有片段的实例myListFragment参考。

我不知道myRepository的实现,但如果我可以猜测,这个类可能是一个Singleton类,所以它驻留在整个应用程序进程的内存中。片段和活动上下文是一个很大的内存块,并且由于Singleton类持有对该内存的引用,因此垃圾收集器无法在其生命周期结束时清除该片段/活动内存,这意味着您的Fragment实例也将在整个应用程序生命周期中驻留在内存中。约meomory泄漏一个博客:https://android.jlelse.eu/memory-leak-patterns-in-android-4741a7fcb570

我可以推荐一个修复问题的方法:

  1. 让您的数据管理器类愚蠢的和无状态。不要在你的数据管理器类中附加一个监听器。相反,请让API对数据进行CRUD操作,并仅将侦听器附加到Fragment类中。当事件被触发时,相应地调用数据管理器的方法。这使得您的数据管理器不会将逻辑与任何特定的Fragment类混合使用,如果您稍后需要在项目中删除Fragments,则无需更改任何内容。

希望这会有所帮助。

+0

我有一个来自myrespository的监听器的内存泄漏,它来自我目前在我的代码中使用的库。 我在分别使用的片段的基类中添加和删除onstart和onstop方法中的侦听器。然而,它显示leakcanary泄漏说它被定义为泄漏的静态变量。我如何解决这个问题? –