ZRAM 與 ZSWAP 在記憶體受限場景下的行為差異

一台 8GB 實體記憶體的機器,同時運行 IDEA、Docker、Chromium——記憶體壓力是常態。常見的應對是把 ZRAM 區塊裝置設為最高優先權的 swap。這套配置確實比純磁碟 swap 快不少,但運行幾天後機器照樣會出現嚴重的延遲抖動:滑鼠卡頓、視窗切換延遲幾秒才回應。

問題不在 ZRAM 本身,在於 回收策略跟儲存後端錯配了

ZRAM vs ZSWAP:架構型態的根本區別

兩者都做記憶體壓縮,但定位完全不同。

ZRAM 是壓縮區塊裝置。 它在核心中註冊為一個 /dev/zramX 區塊裝置,儲存後端是記憶體中的壓縮頁。資料透過 swap_writepage() 流入,走的是標準區塊 I/O 路徑。ZRAM 不知道什麼是冷頁熱頁——它就是個媒介,不參與回收決策。池子滿了就按 swap_info 優先權往下一個 swap 裝置 fallback,毫無策略可言。

ZSWAP 是壓縮快取層。 它掛在交換子系統內部,在 shrink_page_list() 的回收路徑早期就直接攔截頁。ZSWAP 維護壓縮頁的中繼資料,跟核心 LRU 協同工作。它有軟限制 max_pool_percent,池子滿了不是無腦溢出,而是把最冷的頁 Writeback 到後臺磁碟 swap,把空間騰給活躍資料。

這層差異決定了它們在長期高負載下走向完全不同的結果。

LRU 反轉:高速媒介裝垃圾,熱資料困在低速碟

Linux 頁回收的預期行為很簡單:先驅逐 Inactive 冷頁,保住 Active 熱頁。

但看這個配置:

  • /dev/zram0:優先權 32767(最高)
  • 磁碟 swap:優先權 -1

系統啟動階段產生大量一次性初始化資料,這些冷頁在回收時率先進入優先權最高的 ZRAM。等 ZRAM 填滿了,核心工作集(IDEA、Docker 的熱頁)需要換出時,ZRAM 裝不下,被強制重導向到磁碟 swap。

冷資料佔據高速的 ZRAM,熱資料困在低速磁碟上——LRU 的驅逐意圖被 swap 優先權配置徹底推翻。這就是 LRU 反轉,核心 MM 維護者(如 Chris Down)明確反對這種混合配置。

Writeback 策略:被動拒絕 vs 主動老化

特性 ZRAM ZSWAP
觸發機制 手動配置或新版核心支援 zswap_shrink() 自動觸發
策略依據 基於儲存池滿(無策略) 基於 LRU 老化
與 MM 整合度 獨立於 MM 子系統 深度嵌入 Reclaim 路徑

ZSWAP 能動態把最久未存取的頁推到磁碟,釋放池空間給當前活躍頁;ZRAM 填滿之後就只能拒絕服務。

I/O 路徑開銷

ZRAM 的寫入路徑上有完整的區塊層開銷:

記憶體頁 → BIO 分配 → 請求佇列 → I/O 排程 → ZRAM 驅動 → 壓縮

ZSWAP 則繞過了這些:

記憶體頁 → ZSWAP 掛鉤 → 壓縮

不過在桌面場景下,ZSWAP 的實際收益大頭不在於路徑縮短,而在於 減少了低速磁碟 I/O 的發生頻率——LRU 感知的驅逐讓大部分換出停留在壓縮快取層內,只有真正的冷頁才落到磁碟上。

約束與邊界

兩者共同受限的場景:

  • HugeTLB 頁:不支援。
  • Tmpfs 頁:不走 swap 路徑,不受管理。
  • Mlocked 頁:不可換出。

關鍵區別:ZSWAP 必須依賴磁碟 swap 作為後備儲存,它本身就是個快取層;ZRAM 可以獨立存在,不要求有碟。

怎麼選

有磁碟 swap 的桌面 / 伺服器環境,直接用 ZSWAP。在 root 下執行:

swapoff /dev/zram0

echo 1 > /sys/module/zswap/parameters/enabled
echo zstd > /sys/module/zswap/parameters/compressor
echo 50 > /sys/module/zswap/parameters/max_pool_percent

幾點經驗:

  • ZRAM 正確的使用場景是嵌入式、Android 這類無碟環境,它的設計目標就是「在沒有磁碟的情況下提供 swap」;
  • 在有碟的機器上,ZRAM 跟磁碟 swap 混用會製造上述 LRU 反轉問題,應該關掉 ZRAM;
  • ZSWAP 配磁碟 swap 是目前桌面 Linux 上最穩定的記憶體壓力方案,把壓縮當快取,讓真正的冷資料才落碟。

ZRAM 是個好儲存後端,但它沒有回收智慧;ZSWAP 把壓縮和驅逐策略綁在了一起。在有碟環境下,讓它們各司其職——ZSWAP 做熱資料壓縮快取,磁碟 swap 兜底冷資料——才是對的方向。