跳过正文
  1. 文章/

关于Linux的swap那些事情

·2120 字·5 分钟
目录

引子
#

无论在哪个安装 Arch 的教程里面,你都能看到要求你设置一个 swap 分区,但是,这个分区真的那么有必要吗?

我最早听到 swap 这个字,大概是安卓 2.3-4.0 时代吧。那时候的 CPU 性能不行,存储性能也很差,但是人们却执着于把 swap 放在存储卡上面,总共 128M 的内存,要在卡上放 64M 进行交换。不过对于本来就慢的安卓手机,能够有更大的内存以便运行大型一点的游戏,就算慢一点,也比较值得。

然而在现代系统上面,手机厂商又把这个“内存拓展”拿出来,许多人对此嗤之以鼻,然而这完全不是一回事。

把内存变小,而不是放到低速存储上面
#

首先,能够实现这一切的前提,是内存虚拟化。

一个程序看到的大量的地址空间,其实并不是 1:1 的映射到物理内存上面的。通过系统调用 mmap,操作系统记录了一个程序看到的内存是怎么对应到物理内存上去,但是,为什么一定是物理内存上面呢?

于是有了 swap,当我内存不够的时候,直接把程序运行时的内存(匿名页)驱逐到 swap 上面,然后往映射表记录,当再次需要访问他的时候,触发一个“缺页中断”,就把 swap 的内存重新搬回物理内存上面,这一切对于程序来说都是透明的。

随着性能的发展,人们发现,这个把匿名页搬回物理内存的过程实在是太慢了,浪费了大量的 CPU 时间,那么为什么不让做点事情?于是,内存压缩出现了。

ZRAM
#

ZRAM,顾名思义,就是把内存压缩。

不过,人们用的还是 swap 的那套思路,把内存中的一部分划分出来,然后创建一个块设备,然后需要的时候,把内存压缩进去,这就是 ZRAM

我们可以通过 swappiness 参数,控制操作系统内核把内存压缩进入 swap 的激进性,现在的值取 0-200 了,值越高,越倾向于把内存放入交换分区。如果是传统的 swap,那么我们希望不要那么激进,因为磁盘总归是慢的;但是对于一个压缩的内存块来说,应该把这个值取很高,因为对于 zstdlz4 这样的算法来说,压缩/解压的速度非常快。

存到极限
#

如果内存的压力持续增大,ZRAM 会有用完的时候。这又分为两种情况:

1. ZRAM 达到了设置的压缩前的数据的最大值。
#

这时候如果没有配置回写块的时候,系统就会去寻找一个优先级更低的 swap 了。如果没有,那么就很可能触发 OOM

配置了回写块的话,ZRAM 会把其中最少使用的数据驱逐到回写块中。这个回写块跟 swap 是不相容的,只能用于一种用途。

如果这时候需要提取写入到回写块中的数据,那么就直接从磁盘解压到物理内存中,因为是压缩的数据,不仅减少了对磁盘的读写,还不让 CPU 闲着。

2. ZRAM 还没满,但是物理内存就要满了
#

这种情况一般是 ZRAM 块最大值太高了。

同样也会造成 ZRAM 往回写块驱逐匿名页,但是如果回写块写入很慢造成了阻塞,同时内存占用还在增加,那么操作系统可能就触发 OOM 开始杀进程了。

ZSWAP
#

还有另外一种技术,但是我之前都没听说过。

这项技术配置起来感觉更加 native 一点,因为是直接往内核参数里面写。

ZSWAP 其实不会创建一个块,但是需要 swap 的存在,当系统打算往 swap 里面写入数据的时候,ZSWAP 会拦截写入,然后进行压缩到内存中的一部分区域。

ZSWAP 同样会在内存压力高的时候驱逐匿名页到 swap 中,这一点跟 ZRAM 不一样,因为如果长期 ZRAM 占满,那么系统就会转而使用磁盘 SWAP 交换,此时变慢会变得很明显(尤其是磁盘速度较慢的时候)。

Linux 6.8 开始,支持禁用回写块,仅仅用作内存压缩。


所以你会发现,ZRAM 加上了回写块,那么就是普通的 ZSWAP;如果 ZSWAP 禁用了回写块,那么就相当于一个普通的 ZRAM,从使用的角度,确实是这样的。

如何选择
#

既然这两者都可以在使用时相互替代,那么究竟如何选择呢?

桌面环境
#

如果内存足够,更推荐使用 ZSWAP

如要使用休眠,可以考虑禁用回写块。这样 swap 就专注于配置休眠,但这样负载高了就更容易出现 OOM,这点需要权衡,一般也不会跑大型任务的时候考虑休眠吧?

其他环境
#

小内存的设备,比如安卓,更加倾向于 ZRAM。原因是 ZSWAP 要求真实的 SWAP 设备,但是闪存一般来说没那么耐写。

服务器可以使用 ZRAM 加上一个小 SWAP,这样可以很好的避免了内存使用的尖锋,也享受了内存压缩的红利。

不推荐同时使用 ZSWAPZRAM,这样会造成冲突。


两者有什么优势呢?

ZSWAP:管理起来更直观,对于桌面体验来说更加友好。因为是钩子,所以不会出现一个 swap 块。

ZRAM:更适合小内存闪存不可多写的设备。不仅仅是内存压缩,实际上块设备可以格式化来存东西。

观察
#

zswap

这是一个 ZSWAPhtop 图,compressedfrontswap 就是 ZSWAP 工作的事实。

通过简单的计算可以得到压缩率是 26.3%,这也是配置 zstd 的典型压缩率范围。

前置压缩虽然其实占用的是内存中的空间,但是这里算在 swap 里面了, used 里面的 457M 不包括前置交换,由于使用 systemd 禁用了 ZSWAP 使用系统交换空间,所以这里面的内容其实是内核使用的交换空间。


如果是一个 ZRAM 的设备,那么 htop 甚至可以单独调出一条来显示它,从观察角度来说,ZRAM 相对方便一些。

参考
#

(电源管理/挂起与休眠 - Arch Linux 中文维基)[https://wiki.archlinuxcn.org/wiki/%E7%94%B5%E6%BA%90%E7%AE%A1%E7%90%86/%E6%8C%82%E8%B5%B7%E4%B8%8E%E4%BC%91%E7%9C%A0#Disable_zswap_writeback_to_use_the_swap_space_only_for_hibernation]