![进一步阅读](https://linux22.com/image/147794/%E8%BF%9B%E4%B8%80%E6%AD%A5%E9%98%85%E8%AF%BB.png)
我有一台 Debian (Buster) 笔记本电脑8GBRAM 和 16GB 交换。我正在运行一个非常长时间运行的任务。这意味着我的笔记本电脑在过去六天里一直处于开机状态。
在执行此操作时,我定期需要将笔记本电脑用作笔记本电脑。这不应该是一个问题;长时间运行的任务受 I/O 限制,通过 USB 硬盘上的内容进行工作,并且不会占用太多 RAM (<200 MB) 或 CPU (<4%)。
问题是几个小时后,当我再次使用笔记本电脑时,速度会非常缓慢,可能需要 30 分钟才能恢复正常。这非常糟糕,以至于崩溃监视器将各自的应用程序标记为已冻结(尤其是浏览器窗口),并且开始错误地崩溃。
从系统监视器上看,已使用的 2.5 GB 中大约有一半被转移到交换区。我通过删除交换空间确认了这是问题所在(swapoff /dev/sda8
) 确认这是问题所在。如果我让它没有交换空间,即使在 24 小时后,它也几乎立即恢复活力。通过交换,它在前五分钟实际上是一块砖,而只剩下六个小时。我已经确认内存使用量永远不会超过3GB即使我不在。
我尝试过减少交换性(另请参阅:维基百科) 到10
和的值0
,但问题仍然存在。似乎在一天不活动之后,内核认为不再需要整个 GUI,并将其从 RAM 中擦除(将其交换到磁盘)。长时间运行的任务是读取巨大的文件树并读取每个文件。因此,内核可能会误认为缓存会有所帮助。但在一次扫描包含约 10 亿个文件名的 2 TB USB HD 时,额外的 GB RAM 对性能的帮助不大。这是一台廉价的笔记本电脑,硬盘驱动器速度很慢。它根本无法足够快地将数据加载回 RAM。
如何告诉 Linux 仅在紧急情况下使用交换空间?我不想在没有交换的情况下运行。如果发生意外情况,并且操作系统突然需要额外的几 GB,那么我不希望任务被终止,并且更愿意开始使用交换。但目前,如果我启用交换,我的笔记本电脑就无法在我需要时使用。
“紧急情况”的准确定义可能存在争议。但为了澄清我的意思:紧急情况是指系统除了交换或终止进程之外没有任何其他选择。
什么是紧急情况?-你真的要问吗?...我希望你永远不会发现自己身处燃烧的建筑物中!
我不可能对这个问题中可能构成紧急情况的所有内容进行定义。但例如,紧急情况可能是当内核需要大量内存以至于它开始使用以下命令杀死进程时:内存溢出杀手。当内核认为可以通过使用交换来提高性能时,并不出现紧急情况。
最终编辑: 我已经接受了一个答案,该答案正是我在操作系统级别所要求的。未来的读者还应该注意提供应用程序级解决方案的答案。
答案1
一种解决方法是确保内存 cgroup 控制器已启用(我认为即使在半新的内核中也是默认的,否则您需要添加cgroup_enable=memory
到内核命令行)。然后,您可以在具有内存限制的 cgroup 中运行 I/O 密集型任务,这也限制了它可以消耗的缓存量。
如果您使用的是 systemd,则可以在单元或包含它的切片中设置+MemoryAccounting=yes
/MemoryHigh
或MemoryMax
(MemoryLimit
取决于您使用的是 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 &
我发现要让用户工作,我必须使用切片。系统一只需将选项放入服务文件中(或systemctl set-property
在服务上使用)即可工作。
这是一个示例服务(使用 cgroup v1),请注意最后两行。这是系统 (pid=1) 实例的一部分。
[Unit]
Description=mount S3QL filesystem
Requires=network-online.target
After=network-online.target
[Install]
WantedBy=multi-user.target
[Service]
Type=forking
User=s3ql-user
Group=s3ql-user
LimitNOFILE=20000
ExecStartPre=+/bin/sh -c 'printf "S3QL_CACHE_SIZE=%%i\n" $(stat -c "%%a*%%S*.90/1024" -f /srv/s3ql-cache/ | bc) > /run/local-s3ql-env'
ExecStartPre=/usr/bin/fsck.s3ql --cachedir /srv/s3ql-cache/fs1 --authfile /etc/s3ql-authinfo --log none «REDACTED»
EnvironmentFile=-/run/local-s3ql-env
ExecStart=/usr/bin/mount.s3ql --keep-cache --cachedir /srv/s3ql-cache/fs1 --authfile /etc/s3ql-authinfo --cachesize ${S3QL_CACHE_SIZE} --threads 4
ExecStop=/usr/bin/umount.s3ql /mnt/S3QL/
TimeoutStopSec=2m
MemoryAccounting=yes
MemoryLimit=1G
文档位于systemd.resource-control(5)
.
答案2
如今进行如此巨大的交换通常是一个坏主意。当操作系统仅交换几GB内存时,您的系统已经爬死了(就像您所看到的那样)
最好是使用zram
有一个小的备份交换分区。许多操作系统喜欢Chrome操作系统、Android 和各种 Linux 发行版 (卢本图,软呢帽)多年来默认启用 zram,特别是对于 RAM 较少的系统。它是快多了与更换硬盘相比,您可以清楚地感受到这种情况下系统的响应能力。 SSD 上的情况较少,但根据基准测试结果在这里即使使用默认的 lzo 算法,它看起来仍然更快。您可以更改为lz4以稍低的压缩比获得更好的性能。其解码速度为根据官方基准测试,比 lzo 快近 5 倍
实际上Windows 10和苹果系统也使用类似的页面文件压缩默认技术
还有zswap
虽然我从来没有用过它。可能值得一试并比较哪一个更适合您的用例
之后另一个建议是降低那些 IO 密集型进程的优先级并且可能让终端以更高的优先级运行,这样即使系统负载较高,您也可以立即在其上运行命令
进一步阅读
答案3
似乎在一天不活动之后,内核认为不再需要整个 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
正如您所写,您的长时间运行的应用程序不会重用它在初始传递后读取的数据,因此您处于长期缓存没有用的特定情况。然后,按照 Will Crawford 的建议,使用直接 I/O 绕过缓存应该是一个很好的解决方法。
或者,您可以在操作系统认为更换 GUI 应用程序和环境之前通过回显1
或3
伪文件定期刷新文件缓存。/proc/sys/vm/drop_caches
看如何清空 Linux 系统上的缓冲区和缓存?了解详情。
1未使用的含义:在相当长的一段时间内不再被积极使用,内存仍然与其所有者相关。
2放回存储在交换区域上的 RAM 页面。
答案4
这是一个想法,我自己还没有尝试过(很抱歉我现在没有时间尝试这个)。
假设您为后台进程创建一个只有 512MB 内存的小型虚拟机,我不确定您是否希望它有任何交换、您的调用以及关闭主机系统上的交换。