內存是計算機系統(tǒng)最重要的資源之一,當操作系統(tǒng)內存不足時,進程申請內存將會失敗,從而導致其運行異常或者崩潰。
Linux 內核提供swap機制來解決內存不足的情況,其原理是:
當系統(tǒng)內存不足時,內核會將進程不常用的內存交換(寫入)到磁盤中,然后將這些內存歸還給系統(tǒng),系統(tǒng)可以將這些內存繼續(xù)分配給其他需要使用內存的進程。
通過 swap 機制,系統(tǒng)可以將內存分配給需求更迫切的進程。但由于 swap 機制需要進行 I/O 操作,所以一定程度上會影響系統(tǒng)性能。那么是否存在一種能夠節(jié)省內存,而且對性能影響較少的機制呢?
在 Linux-3.14 引入了一種名為zRAM的技術,zRAM 的原理是:將進程不常用的內存壓縮存儲,從而達到節(jié)省內存的使用。如下圖所示:
zRAM 機制建立在 swap 機制之上,swap 機制是將進程不常用的內存交換到磁盤中,而 zRAM 機制是將進程不常用的內存壓縮存儲在內存某個區(qū)域。所以 zRAM 機制并不會發(fā)生 I/O 操作,從而避免因 I/O 操作導致的性能下降。
zRAM原理
由于 zRAM 機制是建立在 swap 機制之上,而 swap 機制需要配置文件系統(tǒng)或塊設備來完成的。所以 zRAM 虛擬一個塊設備,當系統(tǒng)內存不足時,swap 機制將內存寫入到這個虛擬的塊設備中。也就是說,zRAM 機制本質上只是一個虛擬塊設備。
zRAM 的原理如下圖所示:
從上圖可以看出,在開啟了 zRAM 機制的情況下,當系統(tǒng)內存不足時,內核會進行如下操作:
通過 swap 機制從系統(tǒng)中查找一些進程不常用的內存。
將這些不常用的內存交換到 zRAM 塊設備中,而 zRAM 塊設備首先會對這些不常用的內存進行壓縮,然后存儲起來。
把不常用的內存壓縮存儲到 zRAM 塊設備后,swap 機制會把這些不常用的內存歸還給內核。
當進程訪問到這些被交換到 zRAM 塊設備的內存時,swap 機制將會通過 zRAM 塊設備解壓這些內存,并且重新建立與進程的地址映射關系。
啟用zRAM
1. 創(chuàng)建 zRAM 塊設備
要啟用 zRAM,首先需要創(chuàng)建 zRAM 塊設備。要創(chuàng)建 zRAM 塊設備,可以使用以下命令:
modprobezramnum_devices=1
num_devices參數(shù)可以指定創(chuàng)建 zRAM 塊設備的個數(shù),上面命令創(chuàng)建了一個 zRAM 塊設備,可以通過路徑/dev/zram0來訪問這個塊設備。
2. 設置 zRAM 塊設備的大小
創(chuàng)建完 zRAM 塊設備后,可以通過以下命令來設置其空間大小:
echo512M>/sys/block/zram0/disksize
上面命令設置了zram0的大小為 512MB,也就是說,zram0能夠存儲 512MB 壓縮后的數(shù)據(jù)。
3. 壓縮算法選擇
zRAM 機制支持多種壓縮算法,不同的壓縮算法有不同的壓縮比率和壓縮速度,用戶可以按照自身的需求來選擇不同的壓縮算法。
要更改 zRAM 的壓縮算法,可以使用下面命令:
echolzo>/sys/block/zram0/comp_algorithm
上面命令將 zRAM 的壓縮算法更改為lzo,我們也可以通過下面命令來查看內核支持哪些壓縮算法:
cat/sys/block/zram0/comp_algorithm lzo[lz4]
從上面命令的輸出可知,內核支持lzo和lz4兩種壓縮算法。
4. 將 swap 交換設備設置為 zRAM
要將 swap 的交換設備設置為 zRAM 塊設備,可以使用以下命令:
mkswap/dev/zram0
當執(zhí)行完上面這條命令后,內核將會使用zram0作為 swap 的交換設備。
zRAM實現(xiàn)
zRAM 塊設備驅動的實現(xiàn)代碼主要在drivers/block/zram/zram_drv.c文件中,下面我們主要圍繞此文件進行分析。
本文并不會介紹塊設備驅動的編寫流程,只會分析 swap 機制在進行內存交換時,與 zRAM 塊設備驅動的交互。
壓縮內存
當系統(tǒng)內存不足時,內核將會觸發(fā)swap機制。swap 機制首先會從系統(tǒng)中選擇一些進程不常用內存,然后將這些不常用的內存交換到zRAM塊設備中(使用 zRAM 塊設備作為交換設備的情況下)。
當 swap 機制將不常用的內存交換到 zRAM 塊設備時,會調用zram_make_request()函數(shù)處理請求。而zram_make_request()最終會通過調用zram_bvec_write()函數(shù)來壓縮內存,調用鏈如下:
zram_make_request() ->__zram_make_request() ->zram_bvec_rw() ->zram_bvec_write()
我們來分析一下zram_bvec_write()函數(shù)的實現(xiàn),其代碼如下:
staticint zram_bvec_write(structzram*zram,structbio_vec*bvec,u32index,intoffset) { ... //1.獲取需要進行壓縮的內存 page=bvec->bv_page; ... user_mem=kmap_atomic(page); uncmem=user_mem; ... //2.對內存進行壓縮 ret=zcomp_compress(zram->comp,zstrm,uncmem,&clen); ... //3.獲取壓縮后的數(shù)據(jù) src=zstrm->buffer; ... //4.申請一個內存塊保存壓縮后的數(shù)據(jù) handle=zs_malloc(meta->mem_pool,clen); ... cmem=zs_map_object(meta->mem_pool,handle,ZS_MM_WO); //5.將壓縮后的數(shù)據(jù)保存到新申請的內存塊中 memcpy(cmem,src,clen); ... //6.將壓縮后的數(shù)據(jù)登記到zRAM塊設備的表格中 meta->table[index].handle=handle; ... returnret; }
為了簡化分析過程,我們對代碼進行精簡。從上面的代碼可以看出,zRAM 機制對內存進行壓縮的步驟如下:
獲取需要進行壓縮的內存,需要進行壓縮的內存由 swap 機制提供。
通過zcomp_compress()函數(shù)對內存進行壓縮,src指針指向壓縮后的內存地址。
通過zs_malloc()和zs_map_object()函數(shù)申請一塊新的內存塊,大小為壓縮后數(shù)據(jù)的大小。
將壓縮后的數(shù)據(jù)復制到新申請的內存塊中。
將壓縮后的數(shù)據(jù)記錄到zRAM塊設備的表格中。
由于 zRAM 塊設備是建立在內存中的虛擬塊設備,所以其并沒有真實塊設備的特性。真實塊設備會將存儲空間劃分成一個個塊,而zram_bvec_write()函數(shù)的index參數(shù)就是數(shù)據(jù)塊的編號。此參數(shù)有 swap 機制提供,所以 zRAM 塊設備驅動通過 index 參數(shù)作為原始內存數(shù)據(jù)的編號。
一圖勝千言:
zRAM驅動有個數(shù)據(jù)塊表,用來記錄原始內存數(shù)據(jù)對應的壓縮數(shù)據(jù),此表的索引就是數(shù)據(jù)塊的編號。swap 機制會維護此表格的使用情況,如哪個塊是空閑的,哪個塊被占用等。
當內存頁被壓縮后,swap 機制將會把原來的內存頁釋放掉,并且把所有映射到此內存頁的進程解除映射,細節(jié)可以參考 swap 機制相關的資料。
審核編輯:劉清
-
Linux系統(tǒng)
+關注
關注
4文章
593瀏覽量
27392 -
SWAP
+關注
關注
0文章
51瀏覽量
12820 -
zram
+關注
關注
0文章
3瀏覽量
75
原文標題:一文讀懂|zRAM 內存壓縮機制
文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論