一文讀懂|zRAM 內(nèi)存壓縮機制
內(nèi)存是計算機系統(tǒng)最重要的資源之一,當(dāng)操作系統(tǒng)內(nèi)存不足時,進程申請內(nèi)存將會失敗,從而導(dǎo)致其運行異?;蛘弑罎ⅰ?br>
Linux 內(nèi)核提供?swap
?機制來解決內(nèi)存不足的情況,其原理是:
當(dāng)系統(tǒng)內(nèi)存不足時,內(nèi)核會將進程不常用的內(nèi)存交換(寫入)到磁盤中,然后將這些內(nèi)存歸還給系統(tǒng),系統(tǒng)可以將這些內(nèi)存繼續(xù)分配給其他需要使用內(nèi)存的進程。
通過 swap 機制,系統(tǒng)可以將內(nèi)存分配給需求更迫切的進程。但由于 swap 機制需要進行 I/O 操作,所以一定程度上會影響系統(tǒng)性能。那么是否存在一種能夠節(jié)省內(nèi)存,而且對性能影響較少的機制呢?
在 Linux-3.14 引入了一種名為?zRAM
?的技術(shù),zRAM 的原理是:將進程不常用的內(nèi)存壓縮存儲,從而達到節(jié)省內(nèi)存的使用。如下圖所示:

zRAM 機制建立在 swap 機制之上,swap 機制是將進程不常用的內(nèi)存交換到磁盤中,而 zRAM 機制是將進程不常用的內(nèi)存壓縮存儲在內(nèi)存某個區(qū)域。所以 zRAM 機制并不會發(fā)生 I/O 操作,從而避免因 I/O 操作導(dǎo)致的性能下降。
zRAM原理
由于 zRAM 機制是建立在 swap 機制之上,而 swap 機制需要配置?文件系統(tǒng)
?或?塊設(shè)備
?來完成的。所以 zRAM 虛擬一個塊設(shè)備,當(dāng)系統(tǒng)內(nèi)存不足時,swap 機制將內(nèi)存寫入到這個虛擬的塊設(shè)備中。也就是說,zRAM 機制本質(zhì)上只是一個虛擬塊設(shè)備。
zRAM 的原理如下圖所示:

從上圖可以看出,在開啟了 zRAM 機制的情況下,當(dāng)系統(tǒng)內(nèi)存不足時,內(nèi)核會進行如下操作:
通過 swap 機制從系統(tǒng)中查找一些進程不常用的內(nèi)存。
將這些不常用的內(nèi)存交換到 zRAM 塊設(shè)備中,而 zRAM 塊設(shè)備首先會對這些不常用的內(nèi)存進行壓縮,然后存儲起來。
把不常用的內(nèi)存壓縮存儲到 zRAM 塊設(shè)備后,swap 機制會把這些不常用的內(nèi)存歸還給內(nèi)核。
當(dāng)進程訪問到這些被交換到 zRAM 塊設(shè)備的內(nèi)存時,swap 機制將會通過 zRAM 塊設(shè)備解壓這些內(nèi)存,并且重新建立與進程的地址映射關(guān)系。
啟用zRAM
1. 創(chuàng)建 zRAM 塊設(shè)備
要啟用 zRAM,首先需要創(chuàng)建 zRAM 塊設(shè)備。要創(chuàng)建 zRAM 塊設(shè)備,可以使用以下命令:
num_devices
?參數(shù)可以指定創(chuàng)建 zRAM 塊設(shè)備的個數(shù),上面命令創(chuàng)建了一個 zRAM 塊設(shè)備,可以通過路徑?/dev/zram0
?來訪問這個塊設(shè)備。
2. 設(shè)置 zRAM 塊設(shè)備的大小
創(chuàng)建完 zRAM 塊設(shè)備后,可以通過以下命令來設(shè)置其空間大?。?/p>
上面命令設(shè)置了?zram0
?的大小為 512MB,也就是說,?zram0
?能夠存儲 512MB 壓縮后的數(shù)據(jù)。
3. 壓縮算法選擇
zRAM 機制支持多種壓縮算法,不同的壓縮算法有不同的壓縮比率和壓縮速度,用戶可以按照自身的需求來選擇不同的壓縮算法。
要更改 zRAM 的壓縮算法,可以使用下面命令:
上面命令將 zRAM 的壓縮算法更改為?lzo
,我們也可以通過下面命令來查看內(nèi)核支持哪些壓縮算法:
從上面命令的輸出可知,內(nèi)核支持?lzo
?和?lz4
?兩種壓縮算法。
4. 將 swap 交換設(shè)備設(shè)置為 zRAM
要將 swap 的交換設(shè)備設(shè)置為 zRAM 塊設(shè)備,可以使用以下命令:
當(dāng)執(zhí)行完上面這條命令后,內(nèi)核將會使用?zram0
?作為 swap 的交換設(shè)備。
【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【749907784】整理了一些個人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實戰(zhàn)項目及代碼)? ??


零聲白金VIP體驗卡(含基礎(chǔ)架構(gòu)/高性能存儲/golang/QT/音視頻/Linux內(nèi)核)課程:

zRAM實現(xiàn)
zRAM 塊設(shè)備驅(qū)動的實現(xiàn)代碼主要在?drivers/block/zram/zram_drv.c
?文件中,下面我們主要圍繞此文件進行分析。
本文并不會介紹塊設(shè)備驅(qū)動的編寫流程,只會分析 swap 機制在進行內(nèi)存交換時,與 zRAM 塊設(shè)備驅(qū)動的交互。
壓縮內(nèi)存
當(dāng)系統(tǒng)內(nèi)存不足時,內(nèi)核將會觸發(fā)?swap
?機制。swap 機制首先會從系統(tǒng)中選擇一些進程不常用內(nèi)存,然后將這些不常用的內(nèi)存交換到?zRAM
?塊設(shè)備中(使用 zRAM 塊設(shè)備作為交換設(shè)備的情況下)。
當(dāng) swap 機制將不常用的內(nèi)存交換到 zRAM 塊設(shè)備時,會調(diào)用?zram_make_request()
?函數(shù)處理請求。而?zram_make_request()
?最終會通過調(diào)用?zram_bvec_write()
?函數(shù)來壓縮內(nèi)存,調(diào)用鏈如下:
我們來分析一下?zram_bvec_write()
?函數(shù)的實現(xiàn),其代碼如下:
為了簡化分析過程,我們對代碼進行精簡。從上面的代碼可以看出,zRAM 機制對內(nèi)存進行壓縮的步驟如下:
獲取需要進行壓縮的內(nèi)存,需要進行壓縮的內(nèi)存由 swap 機制提供。
通過?
zcomp_compress()
?函數(shù)對內(nèi)存進行壓縮,src
?指針指向壓縮后的內(nèi)存地址。通過?
zs_malloc()
?和?zs_map_object()
?函數(shù)申請一塊新的內(nèi)存塊,大小為壓縮后數(shù)據(jù)的大小。將壓縮后的數(shù)據(jù)復(fù)制到新申請的內(nèi)存塊中。
將壓縮后的數(shù)據(jù)記錄到?
zRAM
?塊設(shè)備的表格中。
由于 zRAM 塊設(shè)備是建立在內(nèi)存中的虛擬塊設(shè)備,所以其并沒有真實塊設(shè)備的特性。真實塊設(shè)備會將存儲空間劃分成一個個塊,而?zram_bvec_write()
?函數(shù)的?index
?參數(shù)就是數(shù)據(jù)塊的編號。此參數(shù)有 swap 機制提供,所以 zRAM 塊設(shè)備驅(qū)動通過 index 參數(shù)作為原始內(nèi)存數(shù)據(jù)的編號。
一圖勝千言:

zRAM驅(qū)動有個數(shù)據(jù)塊表,用來記錄原始內(nèi)存數(shù)據(jù)對應(yīng)的壓縮數(shù)據(jù),此表的索引就是數(shù)據(jù)塊的編號。swap 機制會維護此表格的使用情況,如哪個塊是空閑的,哪個塊被占用等。
當(dāng)內(nèi)存頁被壓縮后,swap 機制將會把原來的內(nèi)存頁釋放掉,并且把所有映射到此內(nèi)存頁的進程解除映射,細節(jié)可以參考 swap 機制相關(guān)的資料。
對內(nèi)存進行解壓縮的過程與壓縮過程相反,有興趣的同學(xué)可以自行閱讀代碼,這里就不進行分析了。
原文作者:Linux內(nèi)核那些事
