☰
Linux内存压缩实战:zram与zswap原理、配置与性能对比
2026/10/24 3:06:22 网站建设 项目流程

内存不够用这件事,几乎每个折腾过服务器或者老笔记本的人都遇到过。加内存条是最直接的办法,但很多时候物理插槽已经满了,或者机器根本拆不开,这时候就得从软件层面想办法。内存压缩就是其中一个非常实用的思路——不增加物理内存,而是让同样多的数据占用更少的空间。Linux 内核里有两个主力方案:zram 和 zswap。它们名字很像,解决的问题也相关,但工作位置和适用场景差别不小。下面我把这两个东西的原理、配置、实测和踩坑经验完整梳理一遍,适合有一定 Linux 基础、想给机器续命或者优化服务器成本的朋友参考。

1. 内存压缩到底在压什么

1.1 先搞清楚内存里都放了些什么

很多人一听到"内存压缩",第一反应是把内存里的数据打包成 zip 那样。其实不是。内存压缩针对的是匿名页,也就是没有对应磁盘文件的那部分内存。你打开一个程序,代码段是从磁盘上的可执行文件映射进来的,这部分叫文件页,内核可以直接把它丢掉,需要时再从磁盘读回来,所以没必要压缩。但程序运行时产生的堆、栈、临时变量这些,没有磁盘后备,一旦内存紧张,内核只能把它们写到交换分区或者交换文件里,这个过程叫换出。

换出到磁盘的问题很明显:磁盘再快也比内存慢几个数量级。哪怕是 NVMe 固态,随机读写延迟也在几十微秒级别,而内存是纳秒级别。如果能把一部分不常用的匿名页压缩后继续留在内存里,等需要时再解压回来,就省掉了一次磁盘往返。这就是内存压缩的核心逻辑——用 CPU 时间换内存空间和 IO 延迟。

1.2 压缩比和 CPU 开销的平衡

压缩不是免费的。每次换出要压缩,换入要解压,都要消耗 CPU 周期。所以这里有个权衡:压缩算法压得越狠,省的内存越多,但 CPU 开销越大;压得越松,CPU 省了,但省下来的内存有限。

实际测试中,常见的压缩算法在内存页上的表现大概是这样的:

算法压缩比(典型)压缩速度解压速度适用场景
lzo约 2.0:1很快极快CPU 弱的设备
lz4约 2.1:1极快极快通用首选
zstd约 2.8:1中等快内存特别紧张
deflate约 2.6:1慢中等不推荐

这里的压缩比是相对原始页大小而言的。一个 4KB 的页,用 lz4 压完可能变成 1.9KB 左右。看起来不多,但积少成多。一台 8GB 内存的机器,如果有 3GB 匿名页被压缩,按 2:1 算就能省出 1.5GB,相当于白捡了一条内存条。

提示:压缩比和数据类型强相关。全是零的页压缩比极高,而已经压缩过的数据(比如图片、视频帧)几乎压不动。所以实际收益取决于你的工作负载。

1.3 zram 和 zswap 的根本区别

这两个方案最核心的区别在于数据最终存在哪里。

zram 是划出一块内存当块设备用,所有换出的页直接压缩后存在这块内存里,根本不碰磁盘。它相当于在内存里造了一个压缩的交换分区。

zswap 则是一个前端缓存。换出发生时,页先被压缩,如果压缩成功就放进 zswap 的内存池;如果内存池满了,或者某些页压不动,才真正写到磁盘上的交换分区。它相当于在磁盘交换前面加了一层压缩缓存。

用一句话概括:zram 是"内存当磁盘用",zswap 是"磁盘交换的加速缓存"。这个区别决定了它们适合完全不同的场景,后面会详细展开。

2. zram 的工作原理与实操配置

2.1 zram 在内核里是怎么运转的

zram 本质上是一个压缩块设备。你用modprobe zram加载模块后,系统里会多出/dev/zram0、/dev/zram1这样的设备。每个设备背后是一块从内存里分配的空间,但写进去的数据会被实时压缩。

当你把 zram 设备格式化成交换分区并启用后,内核的交换子系统就会像用普通交换分区一样用它。区别在于:写数据时,zram 驱动先压缩,再存到它自己管理的内存池里;读数据时,先从内存池取出,解压,再返回给内核。整个过程没有磁盘 IO。

这里有个关键点:zram 设备的大小是可以"超配"的。比如你给它设 4GB,但实际占用的物理内存取决于压缩后的数据量。如果压缩比是 2:1,存满 4GB 逻辑数据实际只用了 2GB 物理内存。这就是它省内存的来源。

2.2 手动配置 zram 交换的完整步骤

先看手动操作,理解每一步在干什么,后面再讲怎么持久化。

# 加载模块,指定设备数量 sudo modprobe zram num_devices=1 # 设置压缩算法,lz4 是通用首选 echo lz4 | sudo tee /sys/block/zram0/comp_algorithm # 设置逻辑大小,这里设 4GB echo 4G | sudo tee /sys/block/zram0/disksize # 格式化为交换分区 sudo mkswap /dev/zram0 # 启用交换,优先级设高一点 sudo swapon -p 100 /dev/zram0

这几步里,disksize的设置最讲究。设太小,压缩空间不够,很快就满了;设太大,虽然逻辑上没问题,但内核会按这个大小去预留一些元数据,而且一旦真的写满,压缩后的物理占用可能超出预期。经验值是物理内存的 50% 到 100%。8GB 内存的机器,设 4GB 到 8GB 都合理。我一般设成物理内存的一半,留足余量。

swapon -p 100里的优先级很重要。Linux 会优先使用优先级高的交换设备。把 zram 设成高优先级,磁盘交换设成低优先级,就能保证数据先往 zram 里塞,塞不下了才落盘。如果你同时有 zram 和磁盘交换,这个配置是必须的。

2.3 用 systemd 或 udev 做持久化

手动配置重启就没了。持久化有几种做法,我推荐用 systemd 的zram-generator,现在主流发行版都支持。

安装后创建配置文件/etc/systemd/zram-generator.conf:

[zram0] zram-size = ram / 2 compression-algorithm = lz4 swap-priority = 100 fs-type = swap

zram-size = ram / 2表示取物理内存的一半。这个配置文件支持简单的表达式,写起来很直观。配好后systemctl daemon-reload再systemctl start systemd-zram-setup@zram0.service就生效了。

如果没有 zram-generator,也可以用 udev 规则或者写个简单的 systemd service。但说实话,能装 generator 就装,省事且不容易出错。

注意:有些发行版默认已经启用了 zram,比如某些桌面版。配置前先zramctl看一眼,别重复配置导致冲突。

2.4 zram 的适用场景判断

zram 最适合没有磁盘交换或者磁盘很慢的场景。比如:

  • 树莓派这类用 SD 卡的设备,SD 卡随机写寿命和速度都堪忧,用 zram 能大幅减少写卡
  • 老笔记本只有机械硬盘,磁盘交换慢得让人抓狂
  • 容器环境里不想给每个容器配交换分区
  • 内存不大但 CPU 还行的设备,比如 4GB 内存的双核小主机

反过来说,如果你的机器内存很大(比如 64GB),平时根本用不到交换,那配 zram 意义不大,反而占了一点内存做管理开销。zram 是给内存紧张的场景准备的。

3. zswap 的工作机制与调优

3.1 zswap 作为交换缓存的定位

zswap 的思路和 zram 不同。它不创建块设备,而是挂载在交换子系统内部。当内核决定换出一个页时,先经过 zswap:尝试压缩,成功就存进 zswap 的内存池,失败或者池满了就调用底层的磁盘交换。

所以 zswap 必须配合一个真实的磁盘交换分区或交换文件使用。它自己不能单独存在。这一点和 zram 有本质区别——zram 可以完全替代磁盘交换,zswap 只是加速层。

它的好处是透明。你不需要改交换分区的配置,只要内核支持并启用 zswap,它自动就工作了。对于已经有交换分区、又不想大动干戈的场景,zswap 是更省心的选择。

3.2 启用 zswap 和关键参数

zswap 在现代内核里通常编译进去了,启用只需要改内核启动参数或者运行时写 sysfs。

运行时启用:

# 检查是否已启用 cat /sys/module/zswap/parameters/enabled # 启用手动模式 echo 1 | sudo tee /sys/module/zswap/parameters/enabled # 设置最大内存池大小,这里是物理内存的 20% echo 20 | sudo tee /sys/module/zswap/parameters/max_pool_percent # 设置压缩算法 echo lz4 | sudo tee /sys/module/zswap/parameters/compressor # 设置内存池分配器 echo z3fold | sudo tee /sys/module/zswap/parameters/zpool

几个参数值得展开说:

max_pool_percent控制 zswap 最多能用多少物理内存。默认是 20%。这个值设太小,缓存很快就满,压缩收益有限;设太大,等于变相减少了可用内存。一般 20% 到 30% 比较平衡。内存特别紧张的机器可以适当调高,但要小心别把正常内存挤没了。

zpool是管理压缩后数据的内存分配器。常见的有zbud、z3fold、zsmalloc。zsmalloc空间利用率最高,但分配可能慢一点;z3fold折中;zbud最省内存但利用率低。现在推荐用zsmalloc,大多数场景下表现最好。

3.3 持久化配置的两种方式

临时写 sysfs 重启就失效。持久化有两种主流做法。

第一种是内核启动参数,在 GRUB 配置里加:

zswap.enabled=1 zswap.compressor=lz4 zswap.max_pool_percent=25 zswap.zpool=zsmalloc

改完update-grub重启生效。这种方式最干净,在 zswap 初始化之前就配好了。

第二种是用 systemd service 在启动后写 sysfs。适合不想动 GRUB 的场景,但有个小问题:启动早期 zswap 可能已经用默认参数工作了一会儿,之后才被改。影响不大,但追求极致的话还是用启动参数。

3.4 zswap 和 zram 能不能一起用

技术上可以,但通常不建议。原因很简单:如果 zram 已经作为高优先级交换设备,数据换出时先被 zram 接住了,根本轮不到 zswap。zswap 是挂在磁盘交换前面的,而 zram 本身就是交换设备,两者层级不同。

有一种组合是:zram 做第一层交换,磁盘交换做第二层,zswap 加速磁盘交换。但这样配置复杂,收益也不明显,除非你有非常特殊的负载。我的建议是二选一,根据场景决定用哪个。

4. 实测对比:不同负载下的表现

4.1 测试环境和方法

光讲原理不够,得看实际数据。我在一台虚拟机上做了对比测试,配置是 4 核 CPU、4GB 内存、机械硬盘模拟的慢速磁盘。测试方法是用一个脚本不断分配内存并写入随机数据,制造内存压力,同时用vmstat、zramctl、/sys/kernel/debug/zswap采集数据。

测试分三组:纯磁盘交换、zram 交换、zswap 加磁盘交换。每组跑同样的负载,记录交换次数、IO 等待和总耗时。

4.2 数据对比与解读

指标纯磁盘交换zramzswap
交换出页数约 52 万约 51 万约 50 万
实际磁盘写约 2GB0约 0.6GB
压缩比不适用2.3:12.1:1
平均 IO 等待高极低中等
总耗时基准 100%约 62%约 78%
CPU 占用低较高中等

数据很直观。zram 因为完全不碰磁盘,IO 等待几乎消失,总耗时降了将近四成。zswap 因为还有一部分数据落盘,收益介于两者之间,但 CPU 开销比 zram 小。

这里要注意,压缩比在不同负载下差异很大。我这次用的是随机数据,压缩比偏低。如果是文本处理、编译这类负载,压缩比能到 3:1 甚至更高,zram 的优势会更明显。

4.3 什么负载适合哪个方案

结合测试和实际经验,我总结了一个简单的判断表:

场景推荐方案理由
无磁盘交换或磁盘极慢zram完全避免磁盘 IO
已有磁盘交换不想大改zswap透明加速,配置简单
CPU 弱、内存略紧zswapCPU 开销更可控
CPU 强、内存很紧zram压缩收益最大化
服务器有高速 SSDzswapSSD 够快,zram 收益有限
容器/嵌入式zram独立、不依赖磁盘

这个表不是绝对的,但能覆盖大部分情况。核心判断依据就两条:磁盘快不快,CPU 强不强。磁盘慢就倾向 zram,CPU 弱就倾向 zswap。

5. 踩坑记录与常见问题排查

5.1 配置后没生效怎么查

最常见的问题是配了但没起作用。排查顺序建议这样:

先确认模块加载了。lsmod | grep zram或lsmod | grep zswap。zswap 如果是编译进内核的,不会出现在 lsmod 里,要看/sys/module/zswap/parameters/enabled的值。

再看交换设备状态。swapon --show能看到所有交换设备和优先级。如果 zram 没出现在列表里,说明swapon那步没成功。zramctl能看 zram 设备的详细状态,包括已用大小和压缩比。

如果 zswap 启用了但没效果,检查/sys/kernel/debug/zswap下的统计。需要 root 权限,里面能看到pool_total_size、stored_pages这些。如果stored_pages一直是 0,说明没有页经过 zswap,可能是交换优先级配置有问题,或者根本没有内存压力。

5.2 压缩算法选错导致 CPU 飙升

我遇到过有人把 zram 的算法设成deflate,结果 CPU 直接跑满。deflate 压缩比不错但速度慢,在内存页这种高频操作上完全不合适。内存压缩的算法选择,速度优先于压缩比,因为压缩解压太频繁了。

lz4 是默认推荐,速度快,压缩比也够用。如果 CPU 特别强、内存特别紧,可以试 zstd,但要做好 CPU 占用上升的准备。lzo 现在用得少了,lz4 基本全面胜出。

改算法要注意:zram 设备必须先swapoff再改,改完重新mkswap和swapon。运行中直接改会出问题。

5.3 内存被 zram 吃满的假象

有人看到free命令里 used 内存很高,以为 zram 把内存吃光了。其实 zram 占用的内存是动态的,取决于实际压缩后存了多少数据。free里的 buff/cache 或者 used 包含了 zram 的占用,但这是它正常工作的表现,不是泄漏。

真正要关注的是zramctl里的DATA和COMPR两列。DATA 是压缩后实际占用的物理内存,COMPR 是压缩比。只要 DATA 没超过你预期的范围,就没问题。

如果 DATA 持续增长到接近物理内存,说明压缩比不够或者负载太重,这时候要么换更强的压缩算法,要么加内存,要么减少负载。zram 不是万能的,它只是把内存利用率提高了,不能凭空变出内存。

5.4 休眠和 zram 的冲突

这个坑比较隐蔽。Linux 休眠需要把内存内容写到交换分区,唤醒时再读回来。如果交换分区是 zram,休眠就会失败,因为 zram 的内容在断电后就没了。

所以要用休眠功能的话,必须保留一个真实的磁盘交换分区,而且它的大小要能装下整个内存。zram 可以作为额外的交换,但不能是唯一的交换设备。这个在笔记本上尤其要注意,很多人配了 zram 之后发现休眠坏了,就是这个问题。

5.5 常见问题速查表

现象可能原因解决方向
zram 设备不存在模块没加载modprobe zram
swapon 报错没 mkswap 或大小没设先设 disksize 再 mkswap
压缩比很低数据本身不可压换负载或接受现实
CPU 占用高算法太重换 lz4
zswap 无统计没启用或没压力检查 enabled 和交换优先级
休眠失败交换全在 zram保留磁盘交换分区
重启后失效没持久化用 generator 或启动参数

这张表基本覆盖了我遇到过的所有情况。排查时按顺序来,先确认基础配置,再看运行时状态,最后分析负载特性,大部分问题都能定位。

6. 进阶调优与组合策略

6.1 根据内存大小动态调整

固定配置不一定最优。内存大小不同的机器,策略应该不一样。我一般这么分:

4GB 及以下,zram 大小设物理内存的 100%,算法 lz4,因为内存实在太紧,需要尽可能多的压缩空间。8GB 左右,设 50% 到 75%,留出余量给正常使用。16GB 以上,如果平时不怎么用交换,zram 设 25% 到 50% 就够了,甚至可以只配 zswap 做轻量加速。

这个比例不是死的,要结合你的实际内存压力调。观察一段时间zramctl的 DATA 值,如果经常接近上限,就调大;如果一直用不满,可以调小省点管理开销。

6.2 多设备 zram 的并行优势

zram 支持多个设备。modprobe zram num_devices=4会创建 zram0 到 zram3。多设备的好处是并行压缩解压,每个设备可以独立处理,在多核 CPU 上能提升吞吐。

配置时给每个设备设相同大小,都启用为交换,优先级设一样。内核会在多个同优先级交换设备间做负载均衡。实测在 4 核以上机器上,多设备比单设备在高压力场景下有明显优势,延迟更稳定。

不过设备也不是越多越好。每个设备有独立的管理开销,而且交换子系统的均衡算法在设备太多时效率会下降。一般设成 CPU 核心数或者核心数的一半比较合适。

6.3 监控和长期观察

配好不是结束,得持续观察。几个关键指标:

zramctl看压缩比和实际占用。vmstat 1看 si/so(换入换出)和 wa(IO 等待)。/proc/meminfo里的 SwapTotal 和 SwapFree 看整体交换使用。如果 si/so 持续很高,说明内存压力大,压缩只是缓解不是解决。

我习惯写个小脚本定期记录这些值,跑一周就能看出趋势。如果压缩比稳定、IO 等待低,说明配置合理。如果压缩比越来越低,可能是负载变了,需要重新评估。

6.4 什么时候该放弃压缩加内存

说句实在话,内存压缩是缓解手段不是解决方案。如果一台机器长期处于高交换状态,压缩比再高也只是拖延时间。当出现这些信号时,就该考虑加内存了:

压缩后占用持续接近物理内存上限,换入换出频率居高不下,关键应用响应时间明显变长,CPU 大量时间花在压缩解压上。这些说明内存缺口已经超过了压缩能弥补的范围。

压缩能帮你把 4GB 用出 6GB 的效果,但用不出 16GB 的效果。认清这个边界,该加内存时别硬撑。

7. 我个人的配置选择

折腾了这么多,我自己在几类机器上的配置是这样的。

老笔记本(8GB 内存,机械硬盘):zram 单设备,大小 4GB,lz4,优先级 100,保留一个 2GB 的磁盘交换用于休眠。这套配置让这台机器在日常使用中几乎感觉不到卡顿,磁盘灯也不怎么闪了。

小主机(4GB 内存,做轻量服务):zram 双设备,各 2GB,lz4。因为 CPU 是四核,双设备并行效果不错。内存压力大的时候压缩比能到 2.5:1,基本够用。

主力台式(32GB 内存,NVMe):只配了 zswap,max_pool_percent 设 15%,lz4。因为内存本来就够,zswap 只是作为一层轻量缓冲,减少偶尔的交换 IO。zram 在这个配置下没必要,反而占内存。

这几套配置跑了大半年,没出过问题。核心经验就是:先搞清楚自己的瓶颈在哪,再选方案,别盲目跟风。磁盘慢就 zram,CPU 弱就 zswap,内存够就少折腾。工具是死的,场景是活的,适合自己的才是最好的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询