一文讀懂linux 下zram

本文轉自https://blog.csdn.net/longwang155069/article/details/51900031

zram 技術的由來:
zram(也稱爲 zRAM,先前稱爲 compcache)是 Linux 內核的一項功能,可提供虛擬內存壓縮。zram 通過在 RAM 內的壓縮塊設備上分頁,直到必須使用硬盤上的交換空間,以避免在磁盤上進行分頁,從而提高性能。由於 zram 可以用內存替代硬盤爲系統提供交換空間的功能,zram 可以在需要交換 / 分頁時讓 Linux 更好利用 RAM ,在物理內存較少的舊電腦上尤其如此。
即使 RAM 的價格相對較低,zram 仍有利於嵌入式設備、上網本和其它相似的低端硬件設備。這些設備通常使用固態存儲,它們由於其固有性質而壽命有限,因而避免以其提供交換空間可防止其迅速磨損。此外,使用 zRAM 還可顯著降低 Linux 系統用於交換的 I/O 。
zram 在 2009 年的時候就進了 kernel 的 staging 目錄,並於 2014 年 3 月 30 日發佈的 3.14 版本正式合併入 Linux 內核主線。在 2014 年 6 月 8 日發佈的 3.15 版本的 Linux 內核中,zram 已可支持 LZ4 壓縮算法,而 LZO 仍然作爲默認的壓縮後端。內核 3.15 中的修改還改進了性能,以及經由 sysfs 切換壓縮算法的能力。
Lubuntu 於 13.10 開始使用 zram 。截至 2012 年 12 月,Ubuntu 考慮爲小內存的計算機默認啓用 zram 。 Google 在 Chrome OS 中使用 zram,它也成爲了 Android 4.4 及以後版本設備的一個選項。
本文主要介紹在 Android 設備上使用的 zram swap,它可以讓小內存的設備在多任務的情況下切換自如,提高用戶體驗。
zram swap 主要原理就是從內存分配一塊區域出來用作 swap 分區,每次如果內存空間不夠了,不是把應用程序殺掉,而是把應用程序所佔用的內存數據複製到 swap 分區,等切換回來的時候就可以直接把這部分數據恢復到內存當中,節省重新開啓所需的時間。而被放到 swap 分區的應用程序,所佔用的內存都是被壓縮過的,比如,微信在普通內存中佔用 50 MB 的空間,如果壓縮率爲 0.4,則放到 swap 分區裏面的數據只需要 20 MB 的空間,這樣 swap 分區裏面就可以存放更多後臺臨時不用的應用程序,變相擴展了內存的大小。
zram 配置步驟:
3.15 之前版本的 kernel
Device Drivers -> Staging drivers (STAGING [=y])
3.15 及之後版本的 kernel
Device Drivers -> [] Block devices -> Compressed RAM block device support
具體的配置項如下:
CONFIG_RESOURCE_COUNTERS=y
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
CONFIG_MEMCG_SWAP_ENABLED=y
CONFIG_MEMCG_KMEM=y
CONFIG_ZRAM=y
CONFIG_TOI_ZRAM_SUPPORT=y
CONFIG_ZRAM_DEBUG=y
zram 塊設備個數設定
如果是將 zram 編譯成模塊,則可以使用下面命令動態加載,這個命令會創建 4 個設備 /dev/zram{0,1,2,3}
modprobe zram num_devices=4
如果是直接將 zram 編譯到內核,那只能在代碼裏面直接修改 num_devices,3.15 之前的版本代碼路徑是 drivers/staging/zram/zram_drv.c,3.15 及之後的版本代碼路徑是 ./drivers/block/zram/zram_drv.c ,默認 zram 設備個數是一個。
壓縮流的最大個數設定
這個是 3.15 版本及以後的 kernel 新加入的功能,3.15 版本之前的 zram 壓縮都是使用一個壓縮流(緩存 buffer 和算法私有部分)實現,每個寫(壓縮)操作都會獨享壓縮流,但是單壓縮流如果出現數據奔潰或者卡住的現象,所有的寫(壓縮)操作將一直處於等待狀態,這樣效率非常低;而多壓縮流的架構會讓寫(壓縮)操作可以並行去執行,大大提高了壓縮的效率和穩定性
查看壓縮流的最大個數,默認是 1
cat /sys/block/zram0/max_comp_streams
設定壓縮流的最大個數
echo 3 > /sys/block/zram0/max_comp_streams
壓縮算法選擇
查看目前支持的壓縮算法
cat /sys/block/zram0/comp_algorithm
lzo [lz4]
修改壓縮算法
echo lzo > /sys/block/zram0/comp_algorithm
zram 內存大小設定
分配部分內存作爲 zram ,大小建議爲總內存的 10%-25%
可以使用數值直接設置內存大小,單位是 bytes
echo $((512
10241024)) > /sys/block/zram0/disksize
也可以使用帶內存單位作爲後綴的方式設置內存大小
echo 256K > /sys/block/zram0/disksize
echo 512M > /sys/block/zram0/disksize
echo 1G > /sys/block/zram0/disksize
啓用 zram 設備爲 swap
mkswap /dev/zram0
swapon /dev/zram0
具體的 zram 相關對外接口說明
Name Access Description
disksize RW 顯示和設置該塊設備的內存大小
initstate RO 顯示設備的初始化狀態
reset WO 重置設備
num_reads RO 讀數據的個數
failed_reads RO 讀數據失敗的個數
num_write RO 寫數據的個數
failed_writes RO 寫數據失敗的個數
invalid_io RO 非頁面大小對齊的I/O請求的個數
max_comp_streams RW 最大可能同時執行壓縮操作的個數
comp_algorithm RW 顯示和設置壓縮算法
notify_free RO 空閒內存的通知個數
zero_pages RO 寫入該塊設備的全爲的頁面的個數
orig_data_size RO 保存在該塊設備中沒有被壓縮的數據的大小
compr_data_size RO 保存在該塊設備中已被壓縮的數據的大小
mem_used_total RO 分配給該塊設備的總內存大小
mem_used_max RW 該塊設備已用的內存大小,可以寫 1 重置這個計數參數到當前真實的統計值
mem_limit RW zram 可以用來保存壓縮數據的最大內存
pages_compacted RO 在壓縮過程中可用的空閒頁面的個數
compact WO 觸發內存壓縮
reset zram
reset zram後,zram的大小就會變爲0,在使用之前必須需要設置大小
echo 1 > /sys/block/zram0/reset
改變zram的大小
如果zram的大小比較小,不能滿足需要。需要就該zram的大小。
root@test:/data # echo $((512
10241024)) > /sys/block/zram0/disksize
sh: echo: write error: Device or resource busy
如果直接設置新的大小,就會提示設置失敗,設備正在使用。所以先需要關閉設備。
root@test:/data # cat /proc/swaps
Filename Type Size Used Priority
/dev/zram0 partition 409596 4456 -1
root@test:/data # swapoff /dev/zram0
root@test:/data # cat /proc/swaps
Filename Type Size Used Priority
root@test:/data #
可以發現zram0已經不屬於交換分區了。接着繼續設置大小
root@test:/data # echo $((512
1024*1024)) > /sys/block/zram0/disksize
sh: echo: write error: Device or resource busy
root@test:/data #
於是發現還是設置失敗,設備正在使用。查看zram的驅動。
static ssize_t disksize_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{

if (init_done(zram)) {
pr_info(“Cannot change disksize for initialized device\n”);
err = -EBUSY;
goto out_destroy_comp;
}
}

可以發現init_done條件不成立,查看init_done函數。
static inline int init_done(struct zram *zram)
{
return zram->meta != NULL;
}

所以想要重新設置大小,在驅動中查看zram->meta在什麼情況下爲NULL
static void zram_reset_device(struct zram zram, bool reset_capacity)
{

zram_meta_free(zram->meta);
zram->meta = NULL;
/
Reset stats */
memset(&zram->stats, 0, sizeof(zram->stats));

zram->disksize = 0;
if (reset_capacity)
    set_capacity(zram->disk, 0);

}
所以設置大小之前還需要執行reset操作。
root@test:/data # echo 1 > /sys/block/zram0/reset
root@test:/data # echo $((51210241024)) > /sys/block/zram0/disksize
root@test:/data #

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章