即使系统内存较低,也能防止Ubuntu冻结

有时候我需要处理大量的数据,希望将其保存在内存中进行处理。有时候我会错误地估计程序所需的内存量,或者调试器会将内存使用量乘以一个超过可用内存的因子。
每当我启动一个占用大量内存的进程时,这是我对一个正常操作系统的期望:尝试占用所有空闲内存,然后礼貌地要求其他非必要的进程释放一些它们不需要的内存,然后写入交换空间。
而Ubuntu为我做的是:占用所有空闲内存,然后要求操作系统将所有必要的服务(gnome会话、终端、键盘)置换到交换空间,然后冻结并等待我拔掉电源。
两个问题:
1. 操作系统怎么能假设任何东西都可能如此重要,以至于可以停止响应用户输入呢? 2. 我该如何告诉Ubuntu永远不要置换必要的服务,并始终对用户输入作出反应,即使某个愚蠢的进程试图占用比系统提供的更多资源?

你安装了多少内存?你的交换空间是多大(在终端中输入“swapon”来查找)?谢谢,Al。 - heynnema
416GB的内存和16GB的交换空间。但这不是重点,这个问题不能通过增加更多的内存来解决。 - Klamann
1尝试以下两种方法之一。1)将swappiness设置更改为10,即在/etc/sysctl.conf中添加vm.swappiness = 10。在此处搜索swappiness以获取更多信息。2)如果swappiness没有帮助...尽管您可能不想这样做...将交换文件的大小增加到1.5x16G,然后查看是否有所改善。请随时告诉我最新情况。祝好,Al - heynnema
@heynnema 在我使用的Ubuntu 14.04版本的内核4.1.13上,/etc/sysctl.conf文件中没有vm.swappiness变量。当在Ubuntu 16.04下启动内核4.7.2时,/etc/sysctl.conf文件甚至不存在,我记得在某个地方读到systemd文档建议使用/etc/sysctl.d/目录下的配置文件来替代sysctl.conf。供参考。 - WinEunuuchs2Unix
1@Klamann我同意增加更多的交换空间无法解决问题。一旦你有一个消耗所有内存和交换空间的破损程序,添加额外的交换空间只会延迟不可避免的结果。 - WinEunuuchs2Unix
@WinEunuuchs2Unix,我的16.04系统包含/etc/sysctl.conf和/etc/sysctl.d,后者是对同一文件的链接。需要将vm.swappiness添加到sysctl.conf中,并重新启动系统,才能生效。在终端中执行sysctl vm.swappiness命令可以查看预修改值,通常为70,修改后应该为10。鉴于楼主不太愿意增加物理内存,更改交换空间是一个简单的步骤,以确定系统是否可以正常运行而不会冻结。根据经验法则,交换空间的大小一般为RAM_SIZE x 1-1.5,因此我建议使用16G x 1.5的交换空间。如果系统上有第二个硬盘,则甚至可以在那里添加交换空间。 - heynnema
当我输入sysctl vm.swappiness时,回应是60。但是当我cat /etc/sysctl.conf时,每一行都被注释掉了,用#表示,并且根本没有出现vm.swappiness参数。同时,在16.04版本下升级到了Kernel 4.7.2。稍后我会重新启动,使用原始的Kernel 4.4,并更新如果有不同的情况。 - WinEunuuchs2Unix
1@WinEunuuchs2Unix,正如我所说的,vm.swappiness=10需要添加到sysctl.conf文件中。有经验的人甚至可以使用sysctl命令即时设置vm.swappiness=10,而无需编辑sysctl.conf文件。祝好,Al ps:等待OP回复。 - heynnema
@heynnema 抱歉,但是它说“尝试以下两种方法之一。1)将swappiness设置为10,即在/etc/sysctl.conf中添加vm.swappiness = 10”。关键词“change”让我误解了。我对此事的无知导致我一开始不够了解,如果我更加了解,我本可以简单地注释掉需要添加的那行代码。这引出了一个问题,如果我没有添加它,为什么我的设置是60呢...嗯...我想这是另一天的调查任务了。 - WinEunuuchs2Unix
让我们在聊天中继续这个讨论。 - heynnema
你在这个问题上有任何进展吗?我也遇到了这个问题一段时间了,这里的建议都没有帮助(vm.swappiness=10, vm.min_free_kbytes=12000)。我有16GB的内存和4GB的交换空间,当它们满了之后,系统就会冻结。内核版本:4.10.0-33-generic。 - Alex Burdusel
完全没有。调整swappiness可以稍微减少流氓进程最终被杀死的时间,但我们仍然需要谈论几分钟系统无响应的问题,而且在恢复控制之后,所有的应用程序和整个操作系统都将被交换,这将需要更多的时间,直到您可以重新开始工作。所以每当我进行内存密集型工作时,我都非常谨慎,如果出错了,我只是重新启动系统。比等待奇迹发生要快得多。这不是一个解决方案,但似乎这就是我们所拥有的:/ - Klamann
@Klamann 看看这个:http://www.oracle.com/technetwork/articles/servers-storage-dev/oom-killer-1911807.html - George Udosen
我认为调整OOM killer的设置无法解决问题,因为OOM killer的工作是在系统内存几乎耗尽(包括交换空间)时销毁进程。核心问题是一旦开始交换,系统就变得无响应,当交换空间被填满并且重新控制后,系统变得非常缓慢,因为数据只有在需要时才从交换空间移回主内存。但是在再次研究后,我终于找到了适合我的解决方法:https://askubuntu.com/a/960633/572764 - Klamann
2019年了,我们仍然面临着同样的问题。这不应该发生——交换空间比内存慢得多,但它不应该导致机器冻结。 - Konrad Gajewski
这个问题真的很烦人……到目前为止还没有解决方案。 - vinicius gati
4个回答

我对这个问题还没有解决方案,但我可以提供两种可能对其他人有兴趣的解决方法:
1) earlyoom 这是一个监控内存使用情况并在达到一定阈值时终止消耗最多内存的进程的服务(关于Linux内核中的OOM killer,请参考thisthis的问题)。我已经用一个无限请求小块内存的演示进程进行了测试。以下是我的第一印象:当我启动这个恶意进程时,它迅速消耗掉我所有的RAM。然后开始进行交换,系统变得不响应。几秒钟后,系统恢复正常。earlyoom的日志显示,在内存和交换使用率都达到90%后,它终止了这个消耗内存的进程。
当交换开始时仍然会有一些烦人的延迟,并且在进程被终止后,通常会有一些其他进程的部分保留在交换空间中,直到它们被请求。但这是一个开始。
2) 禁用交换空间
我知道这是一个有争议的话题,但对于桌面系统和特别是开发机器来说,有时候会出现某个进程试图占用所有内存的情况,这是有道理的:没有交换空间,OOM killer就能按预期工作。当内存耗尽时,它会找到最佳要终止的进程并将其清除。没有延迟,没有滞后。
您可以使用sudo swapoff -a命令在当前会话中禁用交换空间,或者永久性地进行更改
解决这个问题的正确方法当然是在主内存耗尽并开始进行内存交换时,系统仍保持响应,就像没有明天一样。但很显然,这种情况不会很快发生。

4我已经禁用了交换空间,我的系统从低内存(<100MB)直接进入冻结状态。我如何判断OOM killer是否实际启用? - Michael

来自+22.04 LTS

有一个名为systemd-oomd的服务,它会自动监控内存使用情况,并在内存不足时尝试终止进程。它作为systemd的一部分默认安装。要查看当前状态,请输入oomctl。 示例输出:

Dry Run: no
Swap Used Limit: 90.00%
Default Memory Pressure Limit: 60.00%
Default Memory Pressure Duration: 20s
System Context:
        Memory: Used: 4.1G Total: 15.5G
        Swap: Used: 1.0G Total: 3.9G
Swap Monitored CGroups:
        Path: /
                Swap Usage: (see System Context)
Memory Pressure Monitored CGroups:
        Path: /user.slice/user-1000.slice/user@1000.service
                Memory Pressure Limit: 50.00%
                Pressure: Avg10: 0.00 Avg60: 0.02 Avg300: 0.00 Total: 9s
                Current Memory Usage: 3.9G
                Memory Min: 0B
                Memory Low: 0B
                Pgscan: 23663084
                Last Pgscan: 23663084

默认情况下,当内存和交换空间使用率达到90%时开始回收。它使用用户切片控制组(即user@1000.service)上的内存压力来控制,这是大多数应用程序生成的地方,但不适用于system.slice控制组,该控制组生成系统的最关键组件,如NetworkManager和Gnome Display Manager。简而言之,oomd将在释放系统进程之前释放用户进程。要查看systemd-oomd的当前配置,请输入以下命令:
systemd-analyze cat-config systemd/oomd.conf

参考此页面了解他们的工作内容。要编辑特定systemd单元的OOM参数,请在单元文件中添加或编辑此处指定的变量。

我遇到过类似的问题。不知道我的经验是否适用于你...
最近,我发布了一份关于如何在USB上引导时,在循环LVM设备上安装Linux的指南(因此无需在内部磁盘上安装grub,保持其原样)。这是指南: https://github.com/DareDevil73/linux-on-loopback-usb
然后,我遇到了内存负载过高导致系统冻结的问题,并观察到异常的交换空间使用情况(所有RAM被占用,而交换空间几乎为零)。显然,LVM交换分区已挂载并正常工作,但我不知道为什么内核没有按预期使用它。
我尝试了另一种解决方案。我创建了一个交换的loopback文件(非LVM),冻结问题消失了。现在交换文件被正常使用,操作系统再也不会冻结!
请参考https://github.com/DareDevil73/linux-on-loopback-usb#known-issues获取更详细的信息。

请将链接扩展为答案。 - Konrad Gajewski

尝试以下两种方法之一:
1)将swappiness设置从默认的60更改为10,即在/etc/sysctl.conf中添加vm.swappiness = 10(在终端中输入sudo gedit /etc/sysctl.conf),然后重新启动系统。在此处搜索swappiness以获取更多信息。
2)如果swappiness没有帮助...尽管您可能不想这样做...将交换文件的大小增加到1.5x16G,看看是否有所帮助。
保持联系。祝好,Al

我已经设置了一个虚拟机来运行一些测试,因为每隔几秒重新启动我的操作系统真的很烦人。Ubuntu 16.04,2GB RAM,3GB交换空间,20GB磁盘。然后我运行了一个占用大量内存的脚本:使用默认的swappiness(60),系统会冻结,几分钟后,我关闭它,因为恢复时间不可接受。使用swappiness 10,系统会冻结几秒钟,然后可以接受输入,但无法启动任何进程(例如top来终止内存占用)。大约过了一分钟,进程被杀掉。虽然不完美,但我们正在越来越接近目标。 - Klamann
请随时告诉我们最新情况。虚拟机无法真正模拟您实际使用的操作系统,但它可以让您调整设置。如果swappiness对您的问题有所帮助,我会很感兴趣。祝好,Al - heynnema
1啊,太好了。有进展!稍微了解一下swappiness。你可以稍微调整一下值。干杯,Al。 - heynnema
系统冻结时使用了多少交换空间?谢谢,阿尔。 - heynnema
当我的脚本占用了大约1.75GB的2GB内存时(我猜这是开始交换的时候),它会立即冻结,根据swappines值的不同,可能会在一段时间后对我按下ctrl+c做出反应,也可能不会。 - Klamann
有趣。如果你还没有这样做,可以在测试时在终端中运行top命令,观察内存和交换空间的使用情况。尝试调整swappiness值。可以尝试设置为0、1或80。请保持更新。干杯,阿尔。 - heynnema
这是我对swappiness的想法:默认值(60)太糟糕了。10还可以。20和10几乎一样。0比10慢。但即使设置为10,我的系统仍有很长一段时间没有响应,我必须小心地能够用一个按键杀死进程(系统几乎不对按钮做出反应),否则我可能要等到OOM killer被唤醒,这可能需要几分钟的时间。总的来说,这仍然会让系统阻塞太久,对用户输入的反应速度太慢。 - Klamann
将虚拟机的内存更改为4G,看看会发生什么。谢谢,阿尔。 - heynnema
2为什么要这样做呢?增加内存并不能防止系统在我占用了那些内存的情况下出现卡顿。 - Klamann
改变swappiness值会改变对RAM和swap的依赖关系。当值为10且有更多的RAM时,系统将能够:1)更好地处理低RAM情况,或者2)至少允许您的测试脚本运行更长时间(也许允许您的真实应用在冻结系统之前完成)。我们可能需要在聊天中继续这个对话。如果您认为这有帮助,请投票/接受我的回答。谢谢,Al - heynnema