暗色模式

Linux zram:压缩内存当 swap 用

技术教程
2026-08-14
10
0
本文要点
  • zram 是在内存里开一块压缩区域充当 swap:换出的数据先压缩再存放,读写走内存而非磁盘,比磁盘 swap 快一个数量级
  • 创建三步:zramctl -f -s 512M -a lz4 创建设备 → mkswap 初始化 → swapon 启用
  • zramctlDATA/COMPR 两列直接展示压缩效果:内存压力下 37M 数据被压到 12.2M,省下约三分之二内存
  • 调优两点:zram 场景把 vm.swappiness 调高(如 100)让系统优先用快的 zram,再把 vm.page-cluster 设为 0 避免按簇放大换入
  • 开机自动启用用 zram-tools:改 /etc/default/zramswap 里的 ALGO/SIZE/PRIORITYsystemctl enable --now zramswap
  • 所有命令均在 Ubuntu 24.04(内核 6.8)上真实执行验证

什么是 zram:把内存压缩后当 swap 用

上一篇文章《Linux 交换空间:从 swap 文件创建到 swappiness 调优》讲过 swap 是内存不足时的「兜底仓库」,把不活跃的内存页换出到磁盘腾地方。磁盘 swap 虽然能救命,但慢——内存是纳秒级、磁盘是毫秒级,差距近百万倍,高频换入换出会拖垮整个系统。

zram 换了个思路:它不把数据写到磁盘,而是在内存内部划出一块区域,用压缩算法把换出的页面压缩之后再存放。空间不够就压缩来凑——典型办公/服务器负载的压缩率有 2~4 倍,相当于 1G 内存当 2~4G 用。因为后端是内存,zram 的读写速度远快于磁盘 swap,这是它最大的价值。

工作流程如下:

内存页  --换出-->  lz4/zstd 压缩  -->  存入 zram 块设备(仍在 RAM 里)
内存页  <--换入--  解压还原         <--  需要时从 zram 读回

zram 的典型适用场景:

  • 低内存 VPS / 云主机:1~2G 内存跑 Web 服务时,zram 能显著降低 OOM 概率,又比磁盘 swap 快得多;
  • 服务器高可用:磁盘 swap 页频繁写入还会加速 SSD 磨损,zram 把写放大留在内存里,SSD 更省心;
  • Android / 嵌入式:安卓手机默认就在用 zram 提升多任务能力。
与之相关的还有个 zswap:它不自己占一块内存,而是当缓存层架在内存与磁盘 swap 之间,先压缩放进内存、塞不下再写磁盘。zram 与 zswap 二选一即可,本篇文章聚焦 zram。

查看当前的 zram 状态

动手前先看系统现状。zramctlutil-linux 自带)是查看 zram 的标准命令,无参数直接列出所有设备:

zramctl

输出里每一列含义:

含义
NAMEzram 块设备路径,/dev/zram0/dev/zram1
ALGORITHM当前使用的压缩算法(lz4 / lzo-rle / zstd 等)
DISKSIZE设备容量,即「未压缩」的虚拟大小
DATA当前存进去的未压缩数据量
COMPR数据压缩后实际占用的量
TOTAL设备在内存里的总开销(含元数据),通常略大于 COMPR
STREAMS并发压缩流的数量
MOUNTPOINT[SWAP] 表示该设备正被当作交换空间使用

zram 是否参与交换,也能从 /proc/swaps 里看到——Type 列是 partition 的条目就来自 zram 这类块设备。

cat /proc/swaps

内核支持哪些压缩算法,取决于 zram 模块:cat /sys/block/zram0/comp_algorithm(中括号里是当前选中项)。Ubuntu 24.04 内核 6.8 上能看到 lzo lzo-rle [lz4] lz4hc 842 zstd。各算法取舍:lz4 压缩最快、zstd 压缩率最高lzo-rle 介于两者之间,日常推荐 lz4。

创建 zram 设备并启用为 swap

zram 设备是内核动态生成的块设备,三步走:创建 → 初始化 → 启用。

# 1. 确保 zram 模块已加载,并创建一个 512M、lz4 算法的 zram 设备
#    -f 自动分配下一个空闲编号,-s 指定容量,-a 指定压缩算法
modprobe zram
zramctl -f -s 512M -a lz4

# 2. 格式化为交换空间
mkswap /dev/zram0

# 3. 启用(-p 可指定优先级,数值越大越优先被使用)
swapon -p 200 /dev/zram0

四步串起来执行,再核对结果:

创建 zram 设备并启用为 swap

逐行看输出:

  • zramctl -f -s 512M -a lz4 打印 /dev/zram0,说明创建成功并拿到了编号 0;
  • mkswap 输出 Setting up swapspace version 1, size = 512 MiB 和随机 UUID(每次不同);
  • zramctl 里出现一行 /dev/zram0 lz4 512MMOUNTPOINT 已变成 [SWAP]
  • /proc/swaps 里新增 partition 类型的 /dev/zram0(演示机原本已有一块 1G 的 zram1 在当 swap,所以编号从 0 开始并列显示,这并不冲突)。

注意此时 DISKSIZE 512M 只是「虚拟容量」——它在内存里实际占用的空间从 4K 开始,用多少压缩多少,不是一开始就吃掉 512M。这就是 zram 内存友好之处。

对比磁盘 swap 文件的创建流程(fallocatechmod 600mkswapswapon),zram 省略了文件系统与磁盘空间两步,因为是纯内存设备,不需要 chmod,也没有「磁盘写满」的顾虑。

验证压缩效果:内存压力实测

zram 宣称「压缩内存当 swap」,效果到底如何?用 stress 制造内存压力,观察换出到 zram 的数据被压缩了多少:

stress --vm 2 --vm-bytes 900M --timeout 90 >/dev/null 2>&1 & sleep 30; zramctl; free -h

这条命令后台启动两个各占 900M 的压测进程(总计 1.8G,超过这台机器 1.8G 内存),等 30 秒后看实时状态:

内存压力下 zram 的压缩效果

zramctl/dev/zram0 那一行:

NAME       ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
/dev/zram0 lz4           512M  37M 12.2M 13.8M       2 [SWAP]
  • DATA 37M:系统向 zram 换出了 37M 的原始内存页;
  • COMPR 12.2M:压缩后只占 12.2M,压缩率约 3 倍
  • TOTAL 13.8M:算上 zram 的元数据开销,实际从 1.8G 物理内存里「挤」出的约 13.8M,就换来了 37M 的临时空间。

这正是 zram 的核心价值:内存翻倍的代价只是几 M 到几十 M 的压缩开销。同时也说明一个道理——zram 的压缩率取决于数据本身的规律性,stress 这类重复性高的数据能压到 3 倍,真实业务进程一般也有 2~4 倍;如果全是高熵数据(如压缩包、加密流量),压缩率会很低,但至少不会比磁盘 swap 更糟。

更底层:zram 的统计文件

zramctl 只是把内核暴露的统计读了出来。内核 6.8 之后 zram 的内存统计合并到了 /sys/block/zram0/mm_stat

cat /sys/block/zram0/mm_stat
# 输出形如:4096 65 20480 0 20480 0 0 0 0

前三个数字分别对应:原始数据大小(orig_data_size)、压缩后大小(compr_data_size)、实际内存占用(mem_used_total)。老内核(6.8 之前)则是 orig_data_sizecompr_data_sizemem_used_total 三个独立文件。理解这一点,遇到旧教程对不上时就不会懵。

调优:swappiness 与 page-cluster

swap 篇里建议磁盘 swap 场景把 vm.swappiness 调低到 10,减少磁盘写入。但 zram 的「磁盘」其实是内存,写多少次都不磨损、速度又快,所以 zram 场景的逻辑完全反过来——鼓励系统优先用 zram,把换出尽量留在内存里

# 让系统更积极地把数据换出到(速度快的)zram
sysctl vm.swappiness=100

# 永久生效
echo 'vm.swappiness=100' > /etc/sysctl.d/99-zram.conf
sysctl -p /etc/sysctl.d/99-zram.conf

更有针对性的一个参数是 vm.page-cluster。它控制一次换入/换出多少个页面(默认 3 = 2³ = 8 页一批),这是为磁盘设计的——磁盘连续读 8 页比单读快。但 zram 的随机读走内存,批次预取只会白白放大压缩解压的工作量,社区普遍建议对 zram 场景设 0:

echo 'vm.page-cluster=0' >> /etc/sysctl.d/99-zram.conf
sysctl -p /etc/sysctl.d/99-zram.conf
一句话总结调优:磁盘 swap 场景 swappiness 调低(少碰磁盘),zram 场景 swappiness 调高、page-cluster 归零(多压内存、别批量预取)

开机自动启用:zram-tools

重启后 zram 设备会随内核模块消失,手动创建的 swap 自然也没了。开机自动启用最省心的方式是装 zram-tools(Ubuntu/Debian 官方包):

apt install zram-tools

它提供一个 zramswap systemd 服务,配置写在 /etc/default/zramswap

# 压缩算法:速度 lz4 > zstd > lzo;压缩率 zstd > lzo > lz4
ALGO=lz4

# 每个 zram 设备的容量(MiB);设了 PERCENT 时按内存百分比计算并覆盖 SIZE
SIZE=512

# swap 优先级,数值越大越先被使用,建议高于磁盘 swap(默认 100)
PRIORITY=200

配好生效并确认:

zram-tools 开机自启配置

图中 grep 过滤掉注释后,有效配置就是三行 ALGO=lz4 / SIZE=512 / PRIORITY=200;重启服务后 systemctl is-active zramswap 输出 activezramctl 里出现 512M 的 lz4 swap——下次开机它也会自动创建。

systemctl enable --now zramswap   # 开机自启 + 立即启动
⚠️ 一个容易踩的坑zramswap 服务默认操作 /dev/zram0。如果系统里已经手动建过其他 zram 设备(比如本文前面的演示),编号错位会导致服务报错 comp_algorithm: No such file or directory。遇到时先清掉多余设备再启动:swapoff 你的设备zramctl -r 设备,或者干脆 modprobe -r zram 卸载模块后重启服务。

另外还有一套 systemd 原生方案 zram-generator(Fedora 等发行版默认方案),通过 /etc/systemd/zram-generator.conf 的 INI 配置声明设备,喜欢声明式配置的可以了解。Ubuntu 上 apt install zram-generator 即可,二选一,不要两套同时上。

关闭与移除 zram

回收 zram 的顺序与创建相反:先关 swap、再删设备、最后可卸载模块。

# 1. 关闭 swap(数据迁回内存,需保证内存够用)
swapoff /dev/zram0

# 2. 移除 zram 设备,释放它占用的内存
zramctl -r /dev/zram0

# 3. 确认所有 zram 设备都不再需要后,可卸载内核模块
modprobe -r zram

如果用了 zram-tools,关闭则直接 systemctl stop zramswap,并确认 /etc/fstab 里没有残留的 zram 相关行(zram-tools 走 systemd 单元,本身不写 fstab)。

常见问题排查

1. zramctl -f 分配的编号不是 0,或者 zramswap 服务报 comp_algorithm: No such file or directory

zram 设备编号按「最小空闲号」分配,已有设备时新设备会往后排;zram-tools 又硬编码操作 /dev/zram0,两者叠加就会出错。清理多余设备或用 zram-generator 即可,见上文。

2. 内存压力下 swap 数据没进 zram,磁盘 swap 反而被写满

检查优先级:cat /proc/swapsPriority 列,zram 的优先级要高于磁盘 swap 才会被优先使用。创建时用 swapon -p 指定,或 zram-tools 里设 PRIORITY(建议 100+)。

3. zram 被写满怎么办

DISKSIZE 是上限,写满后会继续溢出到磁盘 swap(如果配置了)。可以用 mem_limit 限制单个设备的内存占用上限(写成字节数),或调大 SIZE

4. swapoff 很慢甚至卡住

zram 里存着大量待迁回内存的数据,而内存又紧张时,swapoff 会阻塞等待。先释放内存(停掉压测、清缓存)再操作。

参考资料

发表评论

暂无评论,快来抢沙发吧!