Android 平台執行時有個前提,那就是會持續浪費記憶體,並持續設法用掉所有可用的記憶體。舉例來說,系統會在應用程式關閉後將應用程式留在記憶體內,以便使用者快速切換回這些應用程式。也就是因為這樣,Android 裝置在執行時,通常不會發生大量記憶體未用到的情況。如要在重要系統程序和許多使用者應用程式間妥善配置記憶體,記憶體的管理工作就顯得非常重要。
本頁面會針對 Android 如何為系統和使用者應用程式配置記憶體,討論這方面的基礎概念,也會說明作業系統如何回應記憶體不足的狀況。
記憶體類型
Android 裝置內有三種不同類型的記憶體:RAM、zRAM 和儲存空間。請注意,CPU 和 GPU 皆存取同一個 RAM。
圖 1 記憶體類型 - RAM、zRAM 和儲存空間
RAM 是最快速的記憶體,但是大小通常有限。高階裝置上的 RAM 數量通常最多。
zRAM 是 RAM 用來交換空間的分區。所有內容放入 zRAM 時都會壓縮,並且從 zRAM 複製時解壓縮。這部分的 RAM 會隨頁面進出 zRAM 而增大或縮小。裝置製造商可以設定大小上限。
儲存空間內含所有持續性資料,如檔案系統和其中所有應用程式、程式庫及平台的物件程式碼。儲存空間的容量比其他兩種記憶體要大得多。在 Android 上,儲存空間不會像在其他 Linux 實作項目中用於交換空間,這是因為頻繁寫入可能會耗損記憶體,縮短儲存媒介的壽命。
記憶體頁面
RAM 可以分割成多個「頁面」。一般來說,每個頁面相等於 4 KB 的記憶體。
網頁將視為「免費」或「二手」。可用頁面就是未使用的 RAM。已使用的頁面則是系統目前使用的 RAM,並分為以下幾類:
- 快取:由檔案在儲存空間裡支援的記憶體 (例如程式碼或記憶體對應檔案)。快取記憶體分為兩種類型:
- 匿名:由檔案在儲存空間中支援的記憶體 (例如由
mmap()
分配,且已設定MAP_ANONYMOUS
旗標)- 骯髒:可由
kswapd
移動/壓縮到 zRAM 內,以便增加可用記憶體
- 骯髒:可由
隨著系統主動管理 RAM,可用和已使用的頁面比例也會隨之變化。如要管理記憶體不足的情況,務必瞭解本章節說明的概念。本文件下一章節將會詳細說明這些概念。
記憶體不足時的管理工作
Android 會透過兩種主要機制處理記憶體不足的情況,也就是核心交換 Daemon 和記憶體不足終止工具。
核心交換 Daemon
核心交換 Daemon (kswapd
) 是 Linux kernel 的一部分,可以把已使用的記憶體轉換為可用記憶體。當裝置上的可用記憶體不足時,系統就會啟用 Daemon。Linux kernel 設有可用記憶體的高低門檻。一旦可用記憶體低於最低門檻,kswapd
就會開始取回記憶體。當可用記憶體達到最高門檻時,kswapd
則會停止取回記憶體。
kswapd
可以藉由刪除乾淨頁面取回乾淨頁面,因為這些頁面受到儲存空間支援,並未經過修改。當有程序嘗試處理已經刪除的乾淨頁面時,系統會從儲存空間複製頁面到 RAM。這項作業稱為「需求分頁」。
圖 2. 已刪除由儲存空間支援的乾淨頁面
kswapd
可以把快取的私有骯髒頁面和匿名骯髒頁面移動到 zRAM 內進行壓縮。這樣做即可在 RAM 釋出可用記憶體 (可用頁面)。如有程序嘗試使用 zRAM 內的骯髒頁面,系統就會將該頁面解壓縮並移回 RAM 內。如果系統已終止和某壓縮頁面相關聯的程序,則會從 zRAM 中刪除該頁面。
當可用記憶體數量低於特定門檻時,系統會開始終止程序。
圖 3. 移動到 zRAM 並進行壓縮的骯髒頁面
記憶體不足終止工具
很多時候,kswapd
會無法為系統釋出足夠的記憶體。此時,系統會使用 onTrimMemory()
將記憶體不足的消息告知應用程式,並指出應該減少配置。如果空間不足,核心會開始終止程序,藉此釋出記憶體。為此,記憶體不足終止工具 (LMK) 便可派上用場。
LMK 會使用名為 oom_adj_score
的「記憶體不足」分數為執行中的程序排出優先順序,藉此決定要終止哪些程序。系統會優先終止分數較高的程序。背景應用程式的終止順位最高,系統程序的順位最低。下表由高到低列出 LMK 的分數類別。屬於第一列最高分類別的項目會最先遭到終止:
圖 4. Android 程序,頂端為最高分,而底部為最低分
上表各類別的說明如下:
背景應用程式:先前執行但目前未使用的應用程式。 LMK 會先終止
oom_adj_score
最高的背景應用程式。先前的應用程式:最近使用的背景應用程式。先前的應用程式比背景應用程式優先順位更高 (分數較低),因為相較於背景應用程式,使用者更有可能切換回先前的應用程式。
Google Home 應用程式:啟動器應用程式。如果終止這個應用程式會導致桌布消失。
服務:服務是由應用程式啟動,可能含有雲端同步處理或上傳作業。
可察覺的應用程式:並非在前景執行,但使用者可藉由某些方式察覺的應用程式,這些方式包括執行會顯示小型 UI 的搜尋程序,或聽音樂。
前景應用程式:目前正在使用的應用程式。如果終止前景應用程式,看起來就會像是應用程式當機,可能會讓使用者認為裝置發生問題。
持續性 (服務):這些是裝置的核心服務,如電話通訊系統和 Wi-Fi。
系統:系統程序。如果終止這些程序,可能會重新啟動手機。
原生:由系統使用、非常低階的程序,例如
kswapd
。
裝置製造商可以變更 LMK 的行為。
計算記憶體用量
核心會追蹤系統中的所有記憶體頁面。
圖 5. 不同程序使用的頁面
系統在判斷應用程式使用多少記憶體的時候,必須把共用頁面納入考量。由於存取同一服務或程式庫的應用程式會共用記憶體頁面,例如 Google Play 服務和某個遊戲應用程式可能會共用定位服務,因此很難判斷屬於整個服務和個別應用程式的記憶體各為多少。
圖 6. 由兩個應用程式共用的頁面 (位於中央)
如果想判斷應用程式的記憶體用量,可以使用以下任一種指標:
- 常設集大小 (RSS):該應用程式使用的共用和非共用頁面數量
- 比例集大小 (PSS):該應用程式使用的非共用頁面數量,以及共用頁面的平均分佈情形 (例如在三個程序共享 3 MB 的情況下,每個程序的 PSS 為 1 MB)
- 不重複集大小 (USS):該應用程式使用的非共用頁面數量 (不含共用頁面)
如果作業系統想瞭解所有程序共使用多少記憶體,PSS 就非常實用,因為這個指標不會重複計算頁面。但由於系統需要判斷哪些頁面經過共用,以及由多少程序共用,因此 PSS 需要的計算時間較長。相比之下,RSS 不會區別共用和非共用頁面,所以計算速度較快,較適合用來追蹤記憶體配置的變動情形。
其他資源
- 記憶體管理總覽
- 程序和應用程式生命週期
- 瞭解 Android 記憶體用量 - Google I/O 大會簡報
- Android 記憶體和遊戲 - Google I/O 大會簡報
- Android 記憶體不足終止工具 Daemon
為您推薦
- 注意:系統會在 JavaScript 關閉時顯示連結文字
- 應用程式啟動時間