zram
zram,以前称为 compcache,是一个 Linux 内核模块,用于在 RAM 中创建压缩块设备,即具有即时磁盘压缩的 RAM 磁盘。使用 zram 创建的块设备可以用于交换空间或作为通用 RAM 磁盘。zram 最常见的两个用途是存储临时文件 (/tmp
) 和作为交换设备。最初,zram 只有后一种功能,因此原名“compcache”(“压缩缓存”)。
用作交换空间
最初,创建的 zram 块设备不保留或使用任何 RAM。只有当文件需要或想要被换出时,它们才会被压缩并移动到 zram 块设备中。然后,zram 块设备将根据需要动态增长或缩小。
即使假设 zstd 仅实现保守的 1:2 压缩比(实际数据表明常见的比例为 1:3),zram 也将提供比没有内存压缩的情况下能够在 RAM 中存储更多内容的优势。
- 配置 zram 时,zram 设备的大小控制它可以存储的最大未压缩数据量,而不是最大压缩大小。您可以将 zram 的大小配置为等于甚至大于系统的物理 RAM 容量,只要物理 RAM 上的压缩大小不超过系统的物理 RAM 容量即可。
- 如果相关的 zswap 内核功能保持启用状态,它将阻止 zram 被有效使用。这是因为 zswap 充当 zram 前面的交换缓存,拦截并压缩被驱逐的内存页,然后它们才能到达 zram。尽管 zramctl(8) 的输出如此,但在这种情况下,zswap 的大部分是未使用的。因此,建议在启动前使用内核参数或 sysfs 设置永久禁用 zswap。
- 不支持休眠到 zram 上的交换空间,即使 zram 配置了永久存储上的后备设备。logind 将防止尝试休眠到 zram 上的交换空间。
mem_limit
参数指定 ZRAM 可以用来存储压缩数据的最大内存量。一个简单的起始大小是系统总内存的一半。
手动
要设置一个使用 zstd 压缩算法的 zram 设备,其容量为系统内存的一半,并具有高于正常的优先级(仅适用于当前会话)
# modprobe zram # zramctl /dev/zram0 --algorithm zstd --size "$(($(grep -Po 'MemTotal:\s*\K\d+' /proc/meminfo)/2))KiB" # mkswap -U clear /dev/zram0 # swapon --discard --priority 100 /dev/zram0
要再次禁用它,可以重新启动或运行
# swapoff /dev/zram0 # modprobe -r zram
在 zram 模块的官方文档中提供了所有步骤、选项和潜在问题的详细说明。
对于永久解决方案,请使用以下部分之一的方法。
使用 udev 规则
下面的示例描述了如何在启动时使用单个 udev 规则自动设置 zram 上的交换空间。应该不需要额外的软件包即可使其工作。
显式在启动时加载模块
/etc/modules-load.d/zram.conf
zram
创建以下udev 规则,根据需要调整 disksize
属性
/etc/udev/rules.d/99-zram.rules
ACTION=="add", KERNEL=="zram0", ATTR{initstate}=="0", ATTR{comp_algorithm}="zstd", ATTR{disksize}="4G", RUN="/usr/bin/mkswap -U clear %N", TAG+="systemd"
将 /dev/zram
添加到您的 fstab 中,并设置高于默认的优先级
/etc/fstab
/dev/zram0 none swap defaults,discard,pri=100 0 0
使用 zram-generator
zram-generator 提供 systemd-zram-setup@zramN.service
单元,以自动初始化 zram 设备,而无需用户 启用/启动 模板或其实例。请参阅 zram-generator(8)。
要使用它,安装 zram-generator,并创建包含以下内容的 /etc/systemd/zram-generator.conf
/etc/systemd/zram-generator.conf
[zram0] zram-size = min(ram / 2, 4096) compression-algorithm = zstd
zram-size
是 zram 设备的大小(以 MiB
为单位),您可以使用 ram
来表示总内存。
compression-algorithm
指定用于在 zram 设备中压缩的算法。 cat /sys/block/zram0/comp_algorithm
给出了可用的压缩算法(以及括号中包含的当前算法)。请参阅 zram-generator.conf(5)。
然后运行 daemon-reload,启动 您配置的 systemd-zram-setup@zramN.service
实例(N
与数字实例 ID 匹配,在本例中为 systemd-zram-setup@zram0.service
)。
您可以通过读取 systemd-zram-setup@zramN.service
实例的 单元状态,使用 zramctl(8) 或使用 swapon(8) 来检查您配置的 /dev/zramN
设备的交换状态。
使用 zramswap
zramswapAUR 提供了一个自动化脚本,用于设置具有更高优先级的交换空间,默认大小为系统 RAM 大小的 20%。要在每次启动时自动执行此操作,启用 zramswap.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 的物理 RAM
多个 zram 设备
默认情况下,加载 zram
模块会创建一个 /dev/zram0
设备。
如果您需要多个 /dev/zram
设备,请使用 num_devices
内核模块参数 指定数量,或者根据需要稍后添加它们。
优化 zram 上的交换空间
由于 zram 的行为与磁盘交换空间不同,我们可以配置系统的交换空间以充分利用 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 使用的值。Pop!_OS GitHub pull 请求也链接到 r/Fedora 用户进行的一些测试,该测试确定 vm.page-cluster = 0
是理想的。他们还发现较高的 swappiness 值是理想的,这与 内核文档 的建议相符
- 默认值为 60。
- 对于内存交换空间(如 zram 或 zswap)以及在比文件系统更快的设备上具有交换空间的混合设置,可以考虑超过 100 的值。例如,如果针对交换设备的随机 IO 平均比来自文件系统的 IO 快 2 倍,则 swappiness 应为 133(x + 2x = 200,2x = 133.33)。
在配备硬盘驱动器的系统上,针对 zswap 设备的随机 I/O 将比针对文件系统的 I/O 快几个数量级,因此 swappiness 应约为 200。即使在配备快速 SSD 的系统上,较高的 swappiness 值也可能是理想的。
为 zram 块启用后备设备
可以将 zram 配置为在内存压力下将不可压缩的页面推送到指定的块设备。
要手动添加后备设备
# echo /dev/sdX > /sys/block/zram0/backing_dev
要使用 zram-generator 为您的 zram 块设备添加后备设备,请在您要添加后备设备的 [zramX]
设备下更新 /etc/systemd/zram-generator.conf
,内容如下
/etc/systemd/zram-generator.conf
writeback-device=/dev/disk/by-partuuid/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
将 zram 用于非交换目的
zram 也可以用作通用的 RAM 支持的块设备,例如,/dev/ram
物理内存使用量更少,但性能略低。但是,有一些注意事项
- 没有分区表支持(不会自动创建
/dev/zramxpy
)。 - 块大小固定为 4 kiB。
解决此问题的显而易见的方法是在 zram 之上堆叠一个循环设备,使用 losetup,使用 -b
选项指定所需的块大小,并使用 -P
选项处理分区表并自动创建分区循环设备。
# zramctl -f -s NG
/dev/zramx
将磁盘映像复制到新的 /dev/zramx
,然后创建循环设备。如果磁盘映像具有分区表,则循环设备的块大小必须与分区表使用的块大小匹配,通常为 512 或 4096 字节。
# 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*
的输出取决于磁盘映像的内容。