Android 記憶體管理 — Part 1 (Memory Leak)

York
3 min readJan 25, 2019

--

何謂 Memory Leak?

記憶體洩漏 ( Memory Leak ) 可說是每個 Android 開發者都很常遇到的問題,顧名思義就是指因為疏誤或錯誤導致程式無法釋放不再使用的記憶體。更明確地來說,是指應用程式所分配到的某段記憶體空間在釋放前就失去了控制權,導致該段記憶體無法回收。而在探討可能發生 Memory Leak 的幾種情況前,我們須先了解一下 ART 的 Garbage Collection 機制。

Garbage Collection

所謂的 Garbage Collection,是指在大部分的虛擬機器 (不論是 ART 或 Dalvik) 中,會由一種稱作可達性分析的演算法追蹤記憶體的配置情況,用來決定哪些是未來可能不再被使用的對象 (物件),回收對象所占用的資源。原理則是:有幾個對象作為 root 節點,從這些起始點開始向下搜尋,搜尋的路徑就是各個對象的參照鍊。

例如從下圖來看:從 GC Roots 開始,每個 root 參照到某些對象,而那些對象也同樣參照了其他的對象。由此便能得知目前正在使用及可能不再被使用的物件,進而決定要回收哪些物件所占用的記憶體資源。

了解 GC ( Garbage Collection ) 後,我們便能得知 Android 中的 Memory Leak 就是指:

對象雖然已不再被使用,卻因為一直被 roots 所參照到,導致無法回收對象占用的記憶體空間,因而稱作洩漏 ( Leak )。

何時會發生 Memory Leak?

再來我們看看以下幾種常見記憶體洩漏的情景:

static

當一個變數指定為 static (靜態) 時,代表它從程式開始執行時便產生了,而且它的壽命直到程式結束時才終止。因此當某個對象被靜態變數參照時是無法回收的。

inner class

內部類別的實例會參照到外部類別的實例,因此當內部類別的實例一直存活時,外部類別的實例也就永遠不會被回收。

該如何檢查 Memory Leak?

個人認為目前最容易檢查記憶體洩漏的工具應該是 LeakCanary。使用方法非常簡單,有興趣的人可以自行去官方的 Github 看看如何使用。

這邊直接我們用靜態變數參照到本應回收的物件來示範使用 LeakCanary 的結果。

首先建立兩個 Activity,分別是 MainActivity 和 LeakActivity,MainActivity 有個 Button,按下去後會進入 LeakActivity 的畫面。而在建立 LeakActivity 時,指定一個靜態變數的對象為 LeakActivity 本身,再來只要按下手機的返回鍵後,就會照預期的發生記憶體洩漏了。

LeakActivity

發生洩漏時, LeakCanary 會發出洩漏的通知,另外我們可以開啟 LeakCanary 的 APP 來看看洩漏的詳細資訊:

總結

避免 Memory Leak 的方法便是平常開發時,盡量避免用靜態變數存 Activity, View 等元件,另外盡量少用匿名類別變數來實作非同步工作或是耗時程序。

--

--