zRAM記憶體壓縮技術原理與應用
zRAM記憶體壓縮技術原理與應用
作者: 釋出於:2020-3-8 8:38 分類:記憶體管理
http://www.wowotech.net/memory_management/458.html/comment-page-2#comments
1. 技術背景
說到壓縮這個詞,我們並不陌生,應該都能想到是降低佔用空間,使同樣的空間可以存放更多的東西,類似於我們平時常用的檔案壓縮,記憶體壓縮同樣也是為了節省記憶體。
儘管當前android手機6GB,8GB甚至12GB的機器都較為常見了,但記憶體無論多大,總是會有不夠用的時候。當系統記憶體緊張的時候,會將檔案頁丟棄或回寫回磁碟(如果是髒頁),還可能會觸發LMK殺程序進行記憶體回收。這些被回收的記憶體如果再次使用都需要重新從磁碟讀取,而這個過程涉及到較多的IO操作。就目前的技術而言,IO的速度遠遠慢於這RAM操作速度。因此,如果頻繁地做IO操作,不僅影響flash使用壽命,還嚴重影響系統性能。記憶體壓縮是一種讓IO過程平滑過渡的做法, 即儘量減少由於記憶體緊張導致的IO,提升效能。
2. 主流記憶體壓縮技術
目前linux核心主流的記憶體壓縮技術主要有3種:zSwap, zRAM, zCache。
2.1 zSwap
zSwap是在memory與flash之間的一層“cache”,當記憶體需要swap出去磁碟的時候,先通過壓縮放到zSwap中去,zSwap空間按需增長。達到一定程度後則會按照LRU的順序(前提是使用的記憶體分配方法需要支援LRU)將就最舊的page解壓寫入磁碟swap device,之後將當前的page壓縮寫入zSwap。
zswap本身存在一些缺陷或問題:
-
如果開啟當zswap滿交換出backing store的功能, 由於需要將zswap裡的記憶體按LRU順序解壓再swap out, 這就要求記憶體分配器支援LRU功能。
-
如果不開啟當zswap滿交換出backing store的功能, 和zRam是類似的。
2.2 zRram
zRram即壓縮的記憶體, 使用記憶體模擬block device的做法。實際不會寫到塊裝置中去,只會壓縮後寫到模擬的塊裝置中,其實也就是還是在RAM中,只是通過壓縮了。由於壓縮和解壓縮的速度遠比讀寫IO好,因此在移動終端裝置廣泛被應用。zRam是基於RAM的block device, 一般swap priority會比較高。只有當其滿,系統才會考慮其他的swap devices。當然這個優先順序使用者可以配置。
zRram本身存在一些缺陷或問題:
-
zRam大小是可靈活配置的, 那是不是配置越大越好呢? 如果不是,配置多大是最合適的呢?
-
使用zRam可能會在低記憶體場景由於頻繁的記憶體壓縮導致kswapd程序佔CPU高, 怎樣改善?
-
增大了zRam配置,對系統記憶體碎片是否有影響?
要利用好zRam功能, 並不是簡單地配置了就OK了, 還需要對各種場景和問題都做好處理, 才能發揮最優的效果。
2.3 zCache
zCache是oracle提出的一種實現檔案頁壓縮技術,也是memory與block dev之間的一層“cache”,與zswap比較接近,但zcache目前壓縮的是檔案頁,而zSwap和zRAM壓縮是匿名頁。
zcache本身存在一些缺陷或問題:
-
有些檔案頁可能本身是壓縮的內容, 這時可能無法再進行壓縮了
-
zCache目前無法使用zsmalloc, 如果使用zbud,壓縮率較低
-
使用的zbud/z3fold分配的記憶體是不可移動的, 需要關注記憶體碎片問題
3. 記憶體壓縮主流的記憶體分配器
3.2.1 Zsmalloc
zsmalloc是為ZRAM設計的一種記憶體分配器。核心已經有slub了, 為什麼還需要zsmalloc記憶體分配器?這是由記憶體壓縮的場景和特點決定的。zsmalloc記憶體分配器期望在低記憶體的場景也能很好地工作,事實上,當需要壓縮記憶體進行zsmalloc記憶體分配時,記憶體一般都比較緊張且記憶體碎片都比較嚴重了。如果使用slub分配, 很可能由於高階記憶體分配不到而失敗。另外,slub也可能導致記憶體碎片浪費比較嚴重,最壞情況下,當物件大小略大於PAGE_SIZE/2時,每個記憶體頁接近一般的記憶體將被浪費。
Android手機實測發現,anon pages的平均壓縮比大約在1:3左右,所以compressed anon page size很多在1.2K左右。如果是Slub,為了分配大量1.2K的記憶體,可能記憶體浪費嚴重。zsmalloc分配器嘗試將多個相同大小的物件存放在組合頁(稱為zspage)中,這個組合頁不要求物理連續,從而提高記憶體的使用率。
需要注意的是, 當前zsmalloc不支援LRU功能, 舊版本核心分配的不可移動的頁, 對記憶體碎片影響嚴重, 但最新版本核心已經是支援分配可移動型別記憶體了。
3.2.2 Zbud
zbud是一個專門為儲存壓縮page而設計的記憶體分配器。用於將2個objects存到1個單獨的page中。zbud是可以支援LRU的, 但分配的記憶體是不可移動的。
3.2.3 Z3fold
z3fold是一個較新的記憶體分配器, 與zbud不同的是, 將3個objects存到1個單獨的page中,也就是zbud記憶體利用率極限是1:2, z3fold極限是1:3。同樣z3fold是可以支援LRU的, 但分配的記憶體是不可移動的。
4. 記憶體壓縮技術與記憶體分配器組合對比分析
結合上面zSwap / zRam /zCache的介紹, 與zsmalloc/zbud/z3fold分別怎樣組合最合適呢?
下面總結了一下, 具體原因可以看上面介紹的時候各型別的特點。
zsmalloc | zbud | z3fold | |
---|---|---|---|
zSwap (有實際swap device) | ×(不可用) | √(可用) | √(最佳) |
zSwap (無實際swap device) | √(最佳) | √(可用) | √(可用) |
zRam | √(最佳) | √(可用) | √(可用) |
zCache | ×(不可用) | √(可用) | √(最佳) |
5. zRAM技術原理
本文重點介紹zRam記憶體壓縮技術,它是目前移動終端廣泛使用的記憶體壓縮技術。
5.1 軟體框架
下圖展示了記憶體管理大體的框架, 記憶體壓縮技術處於記憶體回收memory reclaim部分中。
再具體到zRam, 它的軟體架構可以分為3部分, 分別是資料流操作,記憶體壓縮演算法 ,zram驅動。
資料流操作:提供序列或者並行的壓縮和解壓操作。
記憶體壓縮演算法:每種壓縮演算法提供壓縮和解壓縮的具體實現回撥介面供資料操作呼叫。
Zram驅動:建立一個基於ram的塊裝置, 並提供IO請求處理介面。
5.2 實現原理
Zram記憶體壓縮技術本質上就是以時間換空間。通過CPU壓縮、解壓縮的開銷換取更大的可用記憶體空間。
我們主要描述清楚下面這2個問題:
1) 什麼時候會進行記憶體壓縮?
2) 進行記憶體壓縮/解壓縮的流程是怎樣的?
進行記憶體壓縮的時機:
1) Kswapd場景:kswapd是核心記憶體回收執行緒, 當記憶體watermark低於low水線時會被喚醒工作, 其到記憶體watermark不小於high水線。
2) Direct reclaim場景:記憶體分配過程進入slowpath, 進行直接行記憶體回收。
下面是基於4.4核心理出的記憶體壓縮、解壓縮流程。
記憶體回收過程路徑進行記憶體壓縮。會將非活躍連結串列的頁進行shrink, 如果是匿名頁會進行pageout, 由此進行記憶體壓縮存放到ZRAM中, 呼叫路徑如下:
在匿名頁換出到swap裝置後, 訪問頁時, 產生頁訪問錯誤, 當發現“頁表項不為空, 但頁不在記憶體中”, 該頁就是已換到swap區中,由此會開始將該頁從swap區中重新讀取, 如果是ZRAM, 則是解壓縮的過程。呼叫路徑如下:
5.3 記憶體壓縮演算法
目前比較主流的記憶體演算法主要為LZ0, LZ4, ZSTD等。下面截取了幾種演算法在x86機器上的表現。各演算法有各自特點, 有以壓縮率高的, 有壓縮/解壓快的等, 具體要結合需求場景選擇使用。
6. zRAM技術應用
本節描述一下在使用ZRAM常遇到的一些使用或配置,除錯的方法。
6.1 如何配置開啟zRAM
1) 配置記憶體壓縮演算法
下面例子配置壓縮演算法為lz4
echo lz4 > /sys/block/zram0/comp_algorithm
2) 配置ZRAM大小
下面例子配置zram大小為2GB
echo 2147483648 > /sys/block/zram0/disksize
3) 使能zram
mkswap /dev/zram0
swapon /dev/zram0
6.2 swappiness含義簡述
swappiness引數是核心傾向於回收匿名頁到swap(使用的ZRAM就是swap裝置)的積極程度, 原生核心範圍是0~100, 引數值越大, 表示回收匿名頁到swap的比例就越大。如果配置為0, 表示僅回收檔案頁,不回收匿名頁。預設值為60。可以通過節點“/proc/sys/vm/swappiness”配置。
6.3 zRam相關的技術指標
1) ZRAM大小及剩餘空間
Proc/meminfo中可以檢視相關資訊
SwapTotal:swap總大小, 如果配置為ZRAM, 這裡就是ZRAM總大小
SwapFree:swap剩餘大小, 如果配置為ZRAM, 這裡就是ZRAM剩餘大小
當然, 節點 /sys/block/zram0/disksize是最直接的。
2) ZRAM壓縮率
/sys/block/zram/mm_stat中有壓縮前後的大小資料, 由此可以計算出實際的壓縮率
orig_data_size:壓縮前資料大小, 單位為bytes
compr_data_size :壓縮後資料大小, 單位為bytes
3) 換出/換入swap區的總量, proc/vmstat中中有相關資訊
pswpin:換入總量, 單位為page
pswout:換出總量, 單位為page
6.4 zRam相關優化
上面提到zRam的一些缺陷, 怎麼去改善呢?
- zRam大小是可靈活配置的, 那是不是配置越大越好呢? 如果不是配置多大是最合適的呢?
zRam大小的配置比較靈活, 如果zRam配置過大, 後臺快取了應用過多, 這也是有可能會影響前臺應用使用的流暢度。另外, zRam配置越大, 也需要關注系統的記憶體碎片化情。因此zRam並不是配置越大越好,具體的大小需要根據記憶體總大小及系統負載情況考慮及實測而定。
- 使用zRam,可能會存在低記憶體場景由於頻繁的記憶體壓縮導致kswapd程序佔CPU高, 怎樣改善?
zRam本質就是以時間換空間, 在低記憶體的情況下, 肯定會比較頻繁地回收記憶體, 這時kswapd程序是比較活躍的, 再加上通過壓縮記憶體, 會更加消耗CPU資源。 改善這種情況方法也比較多, 比如, 可以使用更優的壓縮演算法, 區別使用場景, 後臺不影響使用者使用的場景非同步進行深度記憶體壓縮, 與使用者體驗相關的場景同步適當減少記憶體壓縮, 通過增加檔案頁的回收比例加快記憶體回收等等。
- 增大了zRam配置,對系統記憶體碎片是否有影響?
使用zRam是有可能導致系統記憶體碎片變得更嚴重的, 特別是zsmalloc分配不支援可移動記憶體型別的時候。新版的核心zsmalloc已經支援可移動型別分配的, 但由於增大了zRam,結合android手機的使用特點, 仍然會有可能導致系統記憶體碎片較嚴重的情況,因些記憶體碎片問題也是需要重點關注的。解決系統記憶體碎片的方法也比較多, 可以結合具體的原因及場景進行優化。
7. 參考資料
-
kernel\Documentation\blockdev\zram.txt
-
kernel\Documentation\vm\zswap.txt
-
kernel\Documentation\sysctl\vm.txt
若在頁首無特別宣告,本篇文章由 Schips 經過整理後釋出。
部落格地址:https://www.cnblogs.com/schips/