APP中經常會存在內存泄漏的問題,一個簡單的測試方法是,屢次進入和退出同一頁面(Activity),使用adb shell中的dumpsys meminfo com.android.settings | grep "Activities"來查看Activity的數量(以com.android.settings爲例)。android
若是隨着屢次進入和退出,Activity的數量一致在增加,沒有降低,那麼便很大有多是內存泄漏的問題。固然有多是GC尚未回收的緣故,若是再顯示地對調用GC回收(DDMS工具的Cause GC按鈕),若是Acitivity的數量仍然沒有下降,那麼機率就更大了。須要從代碼層面進一步分析。shell
今天遇到的例子就是,經過上述方法,看似遇到了內存泄漏,其實不是。工具
關鍵點:經過MAT工具和代碼分析,未回收的對象被system_process進程引用,顯示調用system_process GC便可解決問題,不屬於內存泄漏。測試
案例簡介:在原生Android Open Source Project的Settings APP代碼中,有一個Fragment類叫AccountPreferenceBase,運行在進程com.android.settings中,經過以上方法,發現這個類可能存在內存泄漏,因而在重現問題後,藉助MAT工具,來分析,獲得與此對象相關的引用鏈以下:spa
由上圖可知未被GC回收的AccountPreferenceBase與ContentResolver有關。經過代碼分析,在AccountPreferenceBase中,相關的代碼是以下,對象
進一步分析,在onResume時,調用addStatusChangeListener時,內部會調用RemoteCallbackList的register方法(將callback的binder對象push進一個ArrayMap)。若是再也不頁面退出時,及時從ArrayMap中delete掉此binder對象,就會有內存泄漏的問題。可是咱們在onPause中發現,其實已經調用了removeStatusChangeListener,其內部就會調用unregister方法,從ArrayMap中delete掉正確的binder對象。因此代碼的寫法沒有問題。blog
那是什麼緣由致使GC沒有回收咱們的Activity呢?進程
緣由就是,此ArrayMap是在system_process進程中,並不是在com.android.settings的進程中,delete以後,若是執行一次GC(或者咱們顯示地對system_process調用一次GC),那麼對象就會被回收。引用的settings進程中的Activity也會被回收釋放。內存
因此在此案例中,內存泄漏不存在。ci
所以在遇到內存泄露的狀況時,仍是須要根據代碼來具體分析,GC回收的時機不肯定,可經過顯示地調用GC來回收對象,排除某些內存泄露的可能。固然跨進程時,要調用正確進程的GC來回收。