2017-08-04 77 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泄漏說它被定義爲泄漏的靜態變量。我如何解決這個問題? –