如何仅在紧急情况下使用交换空间?

Phi*_*ing 47 linux memory swap

我有一台带有8 GB RAM 和 16 GB 交换的 Debian (Buster) 笔记本电脑。我正在运行一个很长的运行任务。这意味着我的笔记本电脑在过去六天里一直处于运转状态。

这样做时,我需要定期将笔记本电脑用作笔记本电脑。这应该不是问题;长时间运行的任务受 I/O 限制,处理 USB 硬盘上的内容,并且不占用太多 RAM (<200 MB) 或 CPU (<4%)。

问题是当我在几个小时后回到我的笔记本电脑时,它会非常缓慢,可能需要 30 分钟才能恢复正常。这太糟糕了,以至于崩溃监视器将它们各自的应用程序标记为已冻结(尤其是浏览器窗口),并且事情开始错误地崩溃。

查看系统监视器,大约一半使用的 2.5 GB 被转移到交换中。我已经通过删除交换空间 ( swapoff /dev/sda8) 来确认这是问题所在。如果我在没有交换空间的情况下离开它,即使在 24 小时后它也几乎立即恢复生机。使用交换,前五分钟实际上是一块砖,只剩下六个小时。我已经确认即使我不在时内存使用量也不会超过3 GB

我尝试将swappiness另见:维基百科)减少到10和的值0,但问题仍然存在。似乎在一天不活动后,内核认为不再需要整个 GUI 并将其从 RAM 中擦除(将其交换到磁盘)。长时间运行的任务是读取庞大的文件树并读取每个文件。因此,内核可能会误以为缓存会有所帮助。但是在一次扫描具有约 10 亿个文件名的 2 TB USB 硬盘时,额外的 GB RAM 不会对性能有太大帮助。这是一款价格低廉的笔记本电脑,硬盘速度很慢。它根本无法足够快地将数据加载回 RAM。

如何告诉 Linux 仅在紧急情况下使用交换空间?我不想在没有交换的情况下运行。如果发生意外情况,并且操作系统突然需要额外的几 GB,那么我不希望任务被杀死,而是希望开始使用交换。但目前,如果我启用交换,我的笔记本电脑就无法在需要时使用。

“紧急情况”的确切定义可能是一个有争议的问题。但要澄清我的意思:紧急情况是系统除了交换或终止进程之外别无选择。


什么是紧急情况?-你真的要问吗?...我希望你永远不会发现自己在燃烧的建筑物中!

我不可能在这个问题中定义可能构成紧急情况的所有内容。但是,例如,紧急情况可能是当内核被如此推入内存以至于它开始使用OOM Killer杀死进程时。当内核认为它可以通过使用交换来提高性能时,不是紧急情况。


最终编辑: 我已经接受了一个答案,该答案正是我在操作系统级别所要求的。未来的读者还应该注意提供应用程序级解决方案的答案。

der*_*ert 28

一种解决方法是确保启用内存 cgroup 控制器(我认为即使在最近的内核中也是默认设置,否则您需要添加cgroup_enable=memory到内核​​命令行)。然后,您可以在具有内存限制的 cgroup 中运行 I/O 密集型任务,这也限制了它可以消耗的缓存量。

如果您使用 systemd,您可以在单元或包含它的切片中设置+MemoryAccounting=yesMemoryHigh/MemoryMaxMemoryLimit(取决于您使用的是 cgroup v1 还是 v2)。如果它是一个切片,您可以使用systemd-run在切片中运行程序。

来自我的一个系统的完整示例,用于运行具有内存限制的 Firefox。请注意,这使用 cgroups v2 并设置为我的用户,而不是 root(v2 相对于 v1 的优点之一是将其委托给非 root 是安全的,所以 systemd 这样做了)。

$ systemctl --user cat mozilla.slice 
# /home/anthony/.config/systemd/user/mozilla.slice
[Unit]
Description=Slice for Mozilla apps
Before=slices.target

[Slice]
MemoryAccounting=yes
MemoryHigh=5G
MemoryMax=6G

$ systemd-run --user --slice mozilla.slice --scope -- /usr/bin/firefox &
$ systemd-run --user --slice mozilla.slice --scope -- /usr/bin/thunderbird &
Run Code Online (Sandbox Code Playgroud)

我发现要让用户工作,我必须使用切片。系统一只需将选项放入服务文件(或systemctl set-property在服务上使用)即可工作。

这是一个示例服务(使用 cgroup v1),注意最后两行。这是系统 (pid=1) 实例的一部分。

$ systemctl --user cat mozilla.slice 
# /home/anthony/.config/systemd/user/mozilla.slice
[Unit]
Description=Slice for Mozilla apps
Before=slices.target

[Slice]
MemoryAccounting=yes
MemoryHigh=5G
MemoryMax=6G

$ systemd-run --user --slice mozilla.slice --scope -- /usr/bin/firefox &
$ systemd-run --user --slice mozilla.slice --scope -- /usr/bin/thunderbird &
Run Code Online (Sandbox Code Playgroud)

文档在systemd.resource-control(5).


jll*_*gre 14

似乎在一天不活动后,内核认为不再需要整个 GUI 并将其从 RAM 中擦除(将其交换到磁盘)。

内核正在做正确的事情™相信它。为什么它会在 RAM 中保留未使用的1 个内存并因此基本上浪费它而不是将其用作缓存或其他东西?

我不认为 Linux 内核是无偿的或预期的换出页面,所以如果这样做,必须在 RAM 上存储其他东西,从而提高长期运行任务的性能,或者至少达到这个目标。

如果您知道何时需要提前重新使用您的笔记本电脑,您可以使用at命令 (或crontab) 来安排交换清理 ( swapoff -a;swapon -a)。

由于清理交换可能是矫枉过正,甚至会触发 OOM 杀手,如果出于某种原因,并非所有内容都适合 RAM,您可能只是“取消交换” 2与您想要恢复的正在运行的应用程序相关的所有内容。

一种方法是将调试器附加gdb到每个受影响的进程并触发核心转储生成:

# gdb -p <pid>
...
generate-core-dump /dev/null
...
quit
Run Code Online (Sandbox Code Playgroud)

正如您所写,您的长时间运行的应用程序不会重用它在初始传递后读取的数据,因此您处于长期缓存无用的特定情况下。然后像 Will Crawford 建议的那样使用直接 I/O 绕过缓存应该是一个很好的解决方法。

或者,你可能只是定期呼应刷新文件缓存13/proc/sys/vm/drop_caches伪文件中OS认为这是一个好主意,换出你的GUI应用程序和环境之前。

请参阅如何清空 Linux 系统上的缓冲区和缓存?详情。

1从某种意义上说未使用:在很长一段时间内不再积极使用,内存仍然与其拥有者相关。
2放回存储在交换区的 RAM 页。

  • “我不认为 Linux 内核会无偿或预期地换出页面,所以如果它这样做了,那一定是在 RAM 上存储其他东西,从而提高性能。” ——我觉得这个措辞有点模棱两可。只要有机会(例如,磁盘 I/O 很少),内核就会*肯定* 写入要交换的页面。但是,它不会将它们从 RAM 中删除。这样,您就可以两全其美:如果您很快又需要这些页面,它们已经在 RAM 中了,无需做任何事情。如果出现紧急情况(如 OP 所说),您只需要在 RAM 中释放这些页面,因为 (5认同)
  • ……他们已经在交换了。这正是您*不想*“仅在紧急情况下”使用交换的原因,因为在紧急情况下,系统已经处于压力之下,您最不想要的就是向其添加大量磁盘 I/O。 (3认同)
  • @JörgWMittag 您是否有证据表明 Linux 内核在 I/O 使用率较低时会“以防万一”抢先将页面写入交换区域,即不将它们从 RAM 中释放? (3认同)
  • 感谢您对可能原因的思考。我在问题中添加了一些内容,因为它可能是相关的。我想知道是否有办法降低缓存对应用程序自身内存的优先级。 (2认同)
  • 导致它换出的原因可能是长时间运行的过程:它正在访问磁盘上的文件。内存中的这些文件将比 GUI 的内存使用得更近。 (2认同)

phu*_*clv 13

如今进行如此大的掉期通常是一个坏主意。当操作系统只交换几 GB 的内存进行交换时,您的系统已经爬行至死(就像您看到的那样)

最好与小的备份交换分区一起使用zram。许多操作系统,如ChromeOS、Android 和各种 Linux 发行版(LubuntuFedora)已经默认启用 zram 多年,特别是对于 RAM 较少的系统。它比在 HDD 上交换要快得多,在这种情况下,您可以清楚地感受到系统响应能力。在 SSD 上不那么重要,但根据这里基准测试结果,即使使用默认的 lzo 算法,它似乎仍然更快。您可以更改为lz4以获得更好的性能,同时压缩率更低。根据官方基准,它的解码速度比 lzo 快近 5 倍

事实上Windows 10macOS默认也使用类似的页面文件压缩技术

还有zswap虽然我从来没有用过它。可能值得一试并比较哪个更适合您的用例

之后的另一个建议是降低那些 IO 绑定进程的优先级,并可能让终端以更高的优先级运行,这样即使系统负载很高,您也可以立即在其上运行命令

进一步阅读

  • 我接受这个答案,因为它似乎完全符合我的要求。如果我仍然以降低的优先级启用我的 16GB 交换,那么内核只会在 zswap 耗尽时使用它。IE:“在紧急情况下”。请注意 debian-buster 这很容易设置,只需安装 zram-tools。 (3认同)

小智 10

您正在运行的流程是您自己创建的吗?

如果是这样,可能值得调整您的代码以使用O_DIRECT标志打开文件,该标志引用手册页-

尽量减少进出该文件的 I/O 的缓存影响。通常这会降低性能,但它在特殊情况下很有用,例如当应用程序执行自己的缓存时。文件 I/O 直接进出用户空间缓冲区。O_DIRECT 标志本身努力同步传输数据,但不保证 O_SYNC 标志传输数据和必要的元数据。为了保证同步 I/O,除了 O_DIRECT 之外,还必须使用 O_SYNC。有关进一步讨论,请参阅下面的注释。


X T*_*ian 6

这是一个我自己没有尝试过的想法(很抱歉我现在没有时间对此进行试验)。

假设您为后台进程创建了一个只有 512MB 内存的小型 VM,我不确定您是否希望它具有任何交换、调用和关闭主机系统上的交换。