2014-01-08 91 views
1

我正在研究一個應用程序,其中90%的活動從普通活動繼承並且所有這些活動都泄漏,這意味着如果我從A->B開始,然後從B->Afinish()被稱爲),BonDestroy()被調用,但它仍然泄漏(與MAT檢查)。內存泄漏 - android.os.Message舉辦的Android活動

泄露的活動相當大(10MB〜),所以在來回幾次後,應用程序與OOM崩潰。

我檢查堆轉儲和遵循的路徑GC根所對泄漏的活動,他們都看起來像這樣: enter image description here

所以我想它的東西在滲漏真實的通用超類。我已經檢查過,當活動被破壞時,所有的BroadcastReceivers和監聽器都是未註冊的,並且沒有使用Handler,也沒有可能導致泄漏的匿名內部類(至少在我看來)。

什麼可能是泄漏的原因?任何幫助將非常感激。

編輯

我發現有兩段代碼,當註釋掉活動不漏了:

  1. 是實例化一個ProgressDialog一些代碼行。
  2. 致電postDelayed與匿名Runnable

在第一種情況下,對話框的dismiss()函數在銷燬之前調用,所以我不知道爲什麼這可能是問題所在。在第二種情況下,在中調用Runnable的removeCallbacks,因此理論上它已被正確清理,不是嗎?

乾杯。

+0

我的第一個鏡頭是一個匿名或內部類,它保留對活動上下文的引用。發佈您的活動代碼,以便我們看看它。 –

+0

不幸的是我不能透露代碼,它非常龐大而且很混亂。 MAT截圖告訴你什麼? – Pin

+1

它告訴我你正在泄漏上下文並且它正在被消息隊列保存。首先,驗證活動中是否存在任何非靜態的內部類。來自非靜態內部類的對象持有對其父項的引用,因此您可能需要仔細檢查它。同時仔細檢查您發佈的runnable:運行時間是否過長?只要它在消息隊列中,活動的上下文就不會被破壞。 –

回答

1

問題原來是匿名RunnablepostDelayed。這Runnable被稱爲與基本活動的內容視圖的postDelayed()功能,所以它是這樣的:

@Override 
protected void onResume() { 
    ... 
    mCallback = new Runnable() { ... }; 
    getContentView().postDelayed(mCallback, mDelay); 
} 

令人吃驚的部分是,這個回調是在onPause()刪除:

@Override 
protected void onPause() { 
    ... 
    getContentView().removeCallbacks(mCallback); 
    mCallback = null; 
} 

爲什麼這沒有阻止泄漏對我來說仍然是一個謎。起初,我嘗試使用getContentView().getHandler().removeCallbacksAndMessages(null),它修復了漏洞,但之後應用程序在看似無關的地方完全破解。

最終什麼修復泄漏是創建一個Handler實例和調用postDelayed()removeCallbacks()在這個處理程序。

+0

嗨,真的是一個謎。記錄'getContentView.postDelayed'和'getContentView.removeCallbacks'返回的布爾值會很有趣。看起來像是一個非常糟糕的API設計,讓我在View中公開這些方法。我只會在Handler類中留下這兩種方法。另外,Handler的實現可能會更加強大,以防萬一它不同。 –

+0

我沒有檢查'removeCallbacks'的返回值,它總是返回true,對我來說沒有任何東西顯然是錯誤的。我同意API的設計有點狡猾,不知道爲什麼這些功能在那裏...... – Pin