1. 程式人生 > 程式設計 >Android記憶體洩漏的原因及解決技巧

Android記憶體洩漏的原因及解決技巧

正確的生命週期管理如何防止Android記憶體洩漏

OutOfMemoryException是一個常見的令人沮喪的錯誤,也是導致應用程式意外關閉的主要原因之一。

“如果應用程式昨天執行良好,為什麼現在會發生這種情況?這個問題讓Android的開發者和新手都感到困惑。

導致OutOfMemory異常的潛在原因有很多種,但其中最常見的是記憶體洩漏—應用程式中的記憶體分配從未釋放。本文將解釋如何通過有效的生命週期管理(開發過程中一個重要但經常被忽視的部分)來最小化這種風險。

為什麼安卓系統會發生記憶體洩漏?

問題很簡單。某些物件應該只有一個固定的壽命,當它們的使用壽命結束時,它們需要被刪除。

Android記憶體洩漏的原因及解決技巧

理論上,當程序使用onStop或onDestroy終止時,應該處理該記憶體。但是,濫用物件引用可能會阻止垃圾收集器釋放未使用的物件。例如:如果未使用的物件A引用了未使用的物件B,那麼您將得到兩個不必要的物件,垃圾回收器將永遠不會釋放它們,因為它們正在相互引用。

阻止記憶體洩漏這種情況發生的常見技巧

開發人員可以採取許多步驟來阻止死的活動被困在記憶體中。

  1. 在onResume()/onPause()或onStart()/onStop()中註冊/登出廣播接收器
  2. 不要對檢視/活動/上下文使用靜態變數
  3. 需要儲存對上下文的引用的singleton應該使用applicationContext()或將其包裝到WeakReference中
  4. 注意匿名和非靜態內部類,因為它們包含對其封閉類的隱式引用。
  5. 如果要比父類(如處理程式)更長壽,請使用靜態內部類而不是匿名類。
  6. 如果內部或匿名類是可取消的(如AsyncTask、Thread、RxSubscriptions),則在銷燬活動時取消它。

Android生命週期感知元件

一旦你完成了上面的基本步驟,現在是時候做一些更重要的事情了:應用程式活動的生命週期。如果我們不能正確地管理生命週期,我們最終會在不再需要記憶體的時候掛掉它。

這涉及到許多不同的任務。對於每個活動,我們需要中斷執行緒,去掉RxJava中的訂閱,取消AsyncTask引用,並確保正確刪除該活動的引用(以及與之相關的任何其他活動)。所有這些任務都會消耗開發人員的大量時間。

模型檢視呈現器(MVP)使事情變得更加複雜,MVP是Android中構建使用者介面的常用架構模式。然而,MVP對於從檢視中分離業務邏輯非常有用。

在MVP模式中,View和Presenter都是它們之間行為契約的抽象實現。實現MVP最常見的方法是使用活動/片段作為檢視的實現,併為習慣於引用檢視的演示者使用簡單的實現。

所以我們最終得到了一個帶有Presenter引用的檢視和一個帶有檢視引用的Presenter(提示:這裡有一個潛在的漏洞)。

考慮到這些潛在的困難,我們有必要建立一個適當的管理結構來移除在生命週期中建立的多餘記憶體。有幾種行之有效的方法可以做到這一點:

1. 在Android Studio上使用Android Arch Lifecycle建立支援生命週期的元件

生命週期感知元件是智慧的。例如,它們可以通過除去記憶體來對另一個元件(如活動或片段)的生命週期狀態的更改作出反應。這意味著程式碼更輕,記憶體效率更高。

archlifecycle是Android的一個新庫,它提供了一組工具來構建支援生命週期的元件。庫以抽象的方式工作,這意味著生命週期所有者不再需要擔心管理特定任務和活動的生命週期。

Arch生命週期的關鍵工具和定義如下:

  • 生命週期:一個排序系統,它定義了哪些物件具有Android生命週期,並允許對它們進行監視。
  • LifecycleObserver:一個常規介面,它監視每個被標識為具有Android生命週期的物件,使用一個簡單的公式來處理每個金鑰生命週期事件。
  • @OnLifecycleEvent:可以在實現LifecycleObserver介面的類中使用的註釋。它允許我們設定關鍵生命週期事件,這些事件將在每次啟動時觸發帶註釋的方法。以下是可設定的所有事件的列表:ON_ANY、ON_CREATE、ON_DESTROY、ON_PAUSE、ON_RESUME、ON_START、ON_STOP
  • LifecycleOwner預設為每個可以管理其生命週期的Android元件實現,並讓開發人員控制每個事件。

使用這些工具,我們可以將所有乾淨的任務傳送給它們的所有者(在我們的例子中是演示者),這樣我們就有了一個乾淨的、無洩漏的解耦程式碼(至少在演示者層是這樣)。

下面是一個超級基本的實現,向您展示我們所說的:

interface View: MVPView,LifecycleOwner

class RandomPresenter : Presenter<View>,LifecycleObserver {
 private lateinit var view: View
 override fun attachView(view: View) {
  this.view = view
  view.lifecycle.addObserver(this)
 }

 @OnLifecycleEvent(Lifecycle.Event.On_DESTROY)
 fun onClear() {
	//TODO: clean 
}

2. 使用Android架構檢視模型作為演示者和LiveData

另一種方法是通過使用新的生命週期元件來避免檢視模型的記憶體洩漏。

ViewModel是一個抽象類,它實現一個稱為onClear的函式,當必須刪除某個特定物件時,該函式會自動呼叫。ViewModel是由框架生成的,它附加到建立者的生命週期中(作為一個額外的好處,使用Dagger注入非常容易)

除了使用ViewModel,LiveData還提供了一個重要的通訊渠道。這意味著創造了一個容易觀察到的反應性產物。

這裡最重要的一點是,生命週期所有者可以觀察到LiveData,因此資料傳輸總是由生命週期管理的,而且我們可以確保在使用它們時保留任何引用。

3. 使用LeakCanary和Bugfender

Android記憶體洩漏的原因及解決技巧

除了上述步驟之外,我們還想推薦兩個重要的工具包:LeakCanary,一個用於監視洩漏的流行工具,以及我們自己的Bugfender。

LeakCanary是一個用於Android和Java的記憶體檢測庫。它是開源的,所以有一個龐大的社群支援它,它不僅僅告訴你一個漏洞,它還告訴你可能的原因。

我們的遠端日誌工具Bugfender允許您除錯單個洩漏跟蹤,並擴充套件一個名為DisplayLeakService的類,它讓我們知道何時發生洩漏。然後我們就可以用Bugfender輕鬆登入了。

public class LeakUploadService extends DisplayLeakService {
 override fun afterDefaultHandling(heapDump: HeapDump,result: AnalysisResult,leakInfo: String) {
  if (result.leakFound) {
   Bugfender.d(“LeakCanary”,result.toString())
  }
 }
}

此外,使用者還可以獲得Bugfender的所有其他好處,包括全天候記錄日誌(即使裝置離線)、內建故障報告和易於使用的web控制檯。

以上就是Android記憶體洩漏的原因及解決技巧的詳細內容,更多關於Android記憶體洩漏的資料請關注我們其它相關文章!