zram
zram,旧称为 compcache,是一个用于在内存中创建压缩的块设备的 Linux 内核模块,即带实时磁盘压缩的内存盘。通过 zram 创建的块设备可以用作 swap 或是内存盘。zram 有两个常见的应用场景,一个是储存临时文件(/tmp
),另一个是用作 swap。早期 zram 只有前一个功能,也是它原名 “compcache” (compressed cache) 的由来。
作为 swap 的使用[编辑 | 编辑源代码]
在最开始,创建出的 zram 块设备并不会预留或使用任何内存。仅当有文件需要被或者想要被交换出内存时,它们才会被压缩并移入 zram 块设备。因此,zram 块设备将会根据需要动态地增长或收缩。
即使保守估计 zstd 只能达到 1:2 压缩比(实际中压缩比通常为 1:3),zram 也能提供在内存中存储比不进行内存压缩更多内容的优势。
- 在配置 zram 时设置的 zram 大小指代可存储的最大未压缩数据量,不是指压缩后的数据大小。只要内存中的压缩后数据量小于系统物理内存容量,你甚至可以将 zram 大小配置为等于或大于系统物理内存容量。
- 假如相关的 zswap 内核功能为启用状态,它将阻碍 zram 的有效使用。这是因为 zswap 会在 zram 之前被用作 swap 缓存,并在换出的内存分页到达 zram 前对其进行拦截和压缩。在这种情况下,尽管 zramctl(8) 的输出可能并非如此,实际上大部分 zram 并未被使用。因此,建议在开始前通过内核参数或者 sysfs 设置永久禁用 zswap。
- 不支持在休眠时将内存换出至 zram,即便 zram 被配置在位于永久性存储的设备上。logind 会阻止休眠到配置在 zram 上的交换空间的尝试。
mem_limit
参数指定 ZRAM 可存储的最大压缩后数据量。一开始可以先尝试配置大小为物理内存的一半。
手动应用[编辑 | 编辑源代码]
参考如下配置一个采用 zstd 压缩、容量为系统内存大小一半且优先度较高的 zram 设备 (仅对当前会话生效):
# modprobe zram # zramctl /dev/zram0 --algorithm zstd --size $(($(grep MemTotal /proc/meminfo | tr -dc "0-9")/2)) # mkswap -U clear /dev/zram0 # swapon --priority 100 /dev/zram0
如需禁用,可以重启或执行以下命令:
# swapoff /dev/zram0 # modprobe -r zram # echo 1 > /sys/module/zswap/parameters/enabled
关于每一步操作、配置选项及潜在问题的详细信息可以参考 zram 模组的官方文档。
若需一个持久化的解决方案,请在下属章节所述的方法中任选其一。
使用 udev 规则[编辑 | 编辑源代码]
以下的案例描述了如何通过单个 udev 规则自动在启动时配置 zram 内 swap。该案例无需额外的软件包。
显式地在启动时加载模组:
/etc/modules-load.d/zram.conf
zram
创建如下的 udev 规则(请按需调整 disksize
属性):
/etc/udev/rules.d/99-zram.rules
ACTION=="add", KERNEL=="zram0", ATTR{comp_algorithm}="zstd", ATTR{disksize}="4G", RUN="/usr/bin/mkswap -U clear /dev/%k", TAG+="systemd"
将 /dev/zram
以一个高于默认值的优先度添加到您的 fstab:
/etc/fstab
/dev/zram0 none swap defaults,pri=100 0 0
/dev/disk/by-label/*
和 /dev/disk/by-uuid/*
的符号链接。使用 zram-generator[编辑 | 编辑源代码]
zram-generator包 提供一个 systemd-zram-setup@.service
单元,可自动初始化 zram 设备而无需用户启动/启用相关模板或实例。详见 zram-generator(8) 和 zram-generator.conf(5)。
要创建一个使用 zstd
压缩、大小为所有可用内存容量一半的 zram swap 设备,只需安装 zram-generator包,然后创建包含如下内容的 /etc/systemd/zram-generator.conf
配置文件:
/etc/systemd/zram-generator.conf
[zram0] zram-size = ram / 2 compression-algorithm = zstd
执行 daemon-reload,然后启动您所配置的 systemd-zram-setup@zramN.service
等实例。
您可使用 zramctl(8) 命令,或是通过查阅 systemd-zram-setup@zramN.service
实例的单元状态,来检查您所配置的 /dev/zramN
设备的 swap 状态。
使用 zramswap[编辑 | 编辑源代码]
zramswapAUR 提供一个自动化脚本,可配置一个优先度较高、默认为 20% 系统内存容量的 swap。如需让其自动在启动时执行,请启用 zramswap.service
。
使用 zramd[编辑 | 编辑源代码]
zramdAUR 默认使用 zstd 压缩自动配置 zram,可通过位于 /etc/default/zramd
的文件修改其配置。通过启用 zramd.service
可让其在启动时自动运行。
提示与技巧[编辑 | 编辑源代码]
查看 zram 状态[编辑 | 编辑源代码]
使用 zramctl(8)。示例:
$ zramctl
NAME ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT /dev/zram0 zstd 32G 1.9G 318.6M 424.9M 16 [SWAP]
- DISKSIZE = 32G: 该 zram 设备最多会存储 32 GiB 的未压缩数据
- DATA = 1.9G: 目前, 该 zram 设备上存储着 1.9 GiB (未被压缩的) 数据
- COMPR = 318.6M: 这 1.9 GiB 未被压缩的数据被压缩到了 318.6 MiB
- TOTAL = 424.9M: 包含元信息在内,这 1.9 GiB 未压缩的数据使用了 424.9 MiB 的物理内存
多个 zram 设备[编辑 | 编辑源代码]
初始情况下,加载 zram
模块会创建一个 /dev/zram0
设备。
如果您需要更多的 /dev/zram
设备,使用 num_devices
内核模块参数指定设备的量,或在之后按需添加它们。
优化 zram 上的 swap[编辑 | 编辑源代码]
介于 zram 与磁盘 swap 的行为不同,可以配置系统的 swap 以充分利用 zram 的优势:
/etc/sysctl.d/99-vm-zram-parameters.conf
vm.swappiness = 180 vm.watermark_boost_factor = 0 vm.watermark_scale_factor = 125 vm.page-cluster = 0
该配置的解释:
这些值与Pop!_OS 中使用的值相同。这条 GitHub 上 Pop!_OS 的 pull request 同时链接到了r/Fedora 上一些用户所进行的测试,结果显示 vm.page-cluster = 0
是较为合适的值。此外,他们也发现建议使用较高的 swappniess,这与内核文档中的建议相符。
"默认情况下该值为 60。对于像 zram 或 zswap 这样在内存中的 swap,以及一些混合式的、在相较文件系统来说更为快速的设备上 swap 的配置,应当考虑 100 以上的值。例如,若 swap 设备上的随机读写平均快于文件系统上随机读写的 2 倍,则 swappiness 值应为 133 (x + 2x = 200, 2x = 133.33)。"
在配备硬盘驱动器的系统上,在 zswap 设备上的随机读写会比在文件系统上的读写快若干数量级,因此 swappiness 应为 200 左右。甚至是在配备高速固态硬盘的系统上,较高的 swappiness 值也是理想的。
为 zram 块设备启用后备设备[编辑 | 编辑源代码]
在内存压力较大时,可以配置 zram 将未压缩内存页放入指定的块设备中。
如要手动添加后备设备:
# echo /dev/sdX > /sys/block/zram0/backing_dev
如要通过 zram-generator 为 zram 块设备添加后备设备,可在 /etc/systemd/zram-generator.conf
中对应的 [zramX]
设备下添加如下内容:
/etc/systemd/zram-generator.conf
writeback-device=/dev/disk/by-partuuid/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
将 zram 用于非 swap 用途[编辑 | 编辑源代码]
zram 也可以被用作普通的内存块设备,像是占用较少物理内存,但性能略微下降的 /dev/ram
设备。然而,有几个问题需要注意:
- 无分区表支持(不会自动创建
/dev/zramxpy
)。 - 块大小固定为 4 kiB。
显然,可以通过在 zram 上叠加回环设备来绕过这一问题。使用 losetup,可以使用 -b
参数指定块大小,使用 -P
参数处理分区表并自动创建分区回环设备。
# zramctl -f -s NG
/dev/zramx
将磁盘镜像复制到新创建的 /dev/zram
:
# losetup -f -b 512 -P /dev/zramx
# ls /dev/loop*
/dev/loop0 /dev/loop0p1 /dev/loop0p2
# mount /dev/loop0p1 /mnt/boot # mount /dev/loop0p2 /mnt/root
- zram 设备编号取决于已有的 zram 设备,其大小应足以存放磁盘镜像。
ls /dev/loop*
的输出结果取决于磁盘镜像中的内容。