天天看點

【譯】Activitys, Threads和 記憶體洩露

android程式設計中一個共同的困難就是協調activity的生命周期和長時間運作的任務(task),并且要避免可能的記憶體洩露。思考下面activity的代碼,在它啟動的時候開啟一個線程并循環執行任務。

【譯】Activitys, Threads和 記憶體洩露
【譯】Activitys, Threads和 記憶體洩露

當配置發生變化(如橫豎屏切換)時,會導緻整個activity被銷毀并重新建立,很容易假定android将會為我們清理和回收跟activity相關的記憶體及它運作中的線程。然而,這并非如此。這兩者都會導緻記憶體洩露而且不會被回收, 後果是性能可能顯著地下降。

如果你讀過我前一篇關于handler和内部類的文章,那麼第一種記憶體洩露應該很容易了解。在java中,非靜态匿名類隐式地持有他們的外部類的引用。如果你不小心,儲存這個引用可能導緻activity在可以被gc回收的時候被儲存下來。activity持有一個指向它們整個view繼承樹和它所持有的所有資源的引用,是以如果你洩露了一個,很多記憶體都會連帶着被洩露。

【譯】Activitys, Threads和 記憶體洩露
                 圖1.在10次配置發生變化後,存留在記憶體中的activity執行個體

    每一次配置發生變化後,android系統都會建立一個新的activity并讓舊的activity可以被回收。然而,隐式持有舊activity引用的線程,阻止他們被回收。是以每次洩露一個新的activity,都會導緻所有跟他們關聯的資源都沒有辦法被回收。

    解決方法也很簡單,在我們确定了問題的根源,那麼隻要将線程定義為private static内部類,如下所示:

【譯】Activitys, Threads和 記憶體洩露
【譯】Activitys, Threads和 記憶體洩露

新的線程不會隐式地持有activity的引用,并且activity在配置發生變化後都會變得可以被回收。

第二個問題是每當建立了一個新activity,就會導緻一個thread洩露并且不會被回收。在java中,thread是gc root也就是說在系統中的dalvik virtual machine (dvm)儲存對所有活動 中線程的強引用,這就導緻了這些線程留存下來繼續運作并且不會達到可以被回收的條件。是以你必須要考慮怎樣停止背景線程。下面是一個例子:

【譯】Activitys, Threads和 記憶體洩露
【譯】Activitys, Threads和 記憶體洩露

在android中處理activity生命周期與長時間運作的任務的關系可能很困難并且可能導緻記憶體洩露。下面有一些值得考慮的通用建議:

    優先使用靜态内部類而不是非靜态的。非靜态内部類的每個執行個體都會有一個對它外部activity執行個體的引用。當activity可以被gc回收時,存儲在非靜态内部類中的外部activity引用可能導緻垃圾回收失敗。如果你的靜态内部類需要宿主activity的引用來執行某些東西,你要将這個引用封裝在一個<code>weakreference</code>中,避免意外導緻activity洩露。

    不要假定java最後總會為你清理運作中的線程。在上面的例子中,很容易錯誤地認為使用者退出activity後,activity就會被回收,任何跟這個activity關聯的線程也都将一并被回收。事實上不是這樣的。java線程會繼續運作下去,直到他們被顯式地關閉或者整個process被android系統殺掉。是以,一定要記得記得為背景線程實作對應的取消政策,并且在activity生命周期事件發生的時候使用合理的措施。

【譯】Activitys, Threads和 記憶體洩露

<a href="http://www.androiddesignpatterns.com/2013/04/activitys-threads-memory-leaks.html" target="_blank">譯文連結:activitys, threads, &amp; memory leaks</a>

本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

轉載:http://www.cnblogs.com/kissazi2/p/4125356.html

繼續閱讀