2017-08-04 7 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 = [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

カナリアのリークを使ってどのようにステイスを取得しますか? @マリッサニコラスだけ好奇心。 –

答えて

2

スタックトレースは、がeventListenersアレイのcom.project.newzy.dashboard.myListFragmentへの参照を保持していることを示しています。

私はあなたのmyRepositoryが正確にわからないんだけどUIニーズを破壊することということは(おそらくFragmentmyListFragmentへの参照を保持しています(おそらくそれはObservableとして使用しました)。

この問題を解決するには、myListFragmentが破壊されようとしているときに、それがもはやeventListenersアレイの一部ではないことを確認する必要があります。配列のリスナーをで削除し、onResumeに登録し直してください。

Fragment Lifecycle

+0

私は既にBaseListFragmentという基本クラスからmyListfragmentを拡張しています。そのベースクラスでは、myrepository eventlistenerをonstartに追加してonStopで削除します。十分ではありませんか?私はまた、mylistfragmentであるサブクラスでそれを削除する必要がありますか? onstartやonstopでやってもいいですか?サブクラスでonpauseとonresumeする必要がありますか? –

+0

@MarissaNicholasいいえ、 'onStart'と' onStop'はうまくいくはずです。 'eventlistener'を' onStart'に追加し、 'onStop'で削除していると言っていますか?または、活動/断片?アクティビティ/フラグメントの 'onStop'メソッドが呼び出されると、' eventlistener'からそのアクティビティ/フラグメント自体を削除する必要があります。 – dan

+0

だから、親クラス "BaseListFragment"とサブクラス "mylistfragment"の両方でonstartとonstopを持っています。ただし、親クラスのonstartにmyrepositoryのリスナーを追加し、それを親クラスのonstopから削除します。これまでのところ、サブクラスのonstartとonstopを追加または削除しないでください。私はそれを追加し、それをサブクラスの開始と停止で削除する必要がありますか、そうするにはサブクラスでonresumeとonpauseメソッドを作成する必要がありますか? –

0

あなたのmyRepositoryクラスが断片インスタンスmyListFragmentへの参照を保持しているようです。

myRepositoryの実装はわかりませんが、私が推測できるのであれば、このクラスはおそらくシングルトンクラスであるため、アプリケーションプロセス全体のメモリに常駐しています。フラグメントとアクティビティのコンテキストは大きなメモリチャンクであるため、Singletonクラスはそのメモリへの参照を保持するため、ライフサイクルが終了するとFragment/Activityメモリをクリアすることはできません。 。 meomoryリーク約ブログ:https://android.jlelse.eu/memory-leak-patterns-in-android-4741a7fcb570

私はあなたの問題に対する一つの修正をお勧めすることができます:

  1. は、あなたのデータマネージャクラスはダムとステートレスください。データマネージャークラスの内部にリスナーを接続しないでください。代わりに、CRUD操作をデータに作成するAPIを作成し、Fragmentクラスにリスナーを追加します。イベントがトリガされたら、データマネージャのメソッドを適切に呼び出します。これにより、データマネージャーは、後でプロジェクトでフラグメントを削除する必要がある場合は、何も変更する必要のない特定のフラグメントクラスとロジックを混在させません。

これが役に立ちます。

+0

私は自分のコードで現在使用しているライブラリからのmyrespositoryのリスナーからメモリリークを受けています。 私が使用するフラグメントのベースクラスのonstartメソッドとonstopメソッドでリスナーを追加したり削除したりします。しかし、それは流出した静的変数として定義されていると言って、流出の漏れを示しています。これにどのように対処しますか? –

関連する問題