Ben*_*ela 66 memory linux swap oom
如果一个进程需要大量内存,系统会将所有其他进程移动到交换文件中。似乎包括必要的进程,如 X11 服务器或终端。
因此,如果一个进程继续无限制地分配,一切都会变得无响应,直到该进程被 OOM 杀手杀死。我的笔记本电脑似乎特别灵敏,反应非常糟糕。我只是花了整整一个小时等待进程终止,在此期间甚至无法移动鼠标光标。
如何避免这种情况?
1)禁用交换=>我经常启动很多然后变得不活动的进程。不活动的应该移到交换区。
2) 买个 SSD => 太贵了
3) 设置最大内存 ulimit => 但如果程序需要合理的大量内存,它就会失败。问题不是它使用太多,而是它抑制了其他进程
4) 将重要的程序(X11、bash、kill、top 等)保存在内存中并且永远不要交换那些 => 可以这样做吗?如何?也许只交换大程序?
5) ?
JPv*_*iel 62
ulimit -v,并且可能使用 中的as选项设置硬或软限制limits.conf)。这曾经工作得很好,但是由于 WebKit 的引入gigacage,许多 gnome 应用程序现在期望无限的地址空间并且无法运行!sysctl vm.overcommit_memory,sysctl vm.overcommit_ratio但这种方法并没有为我工作了。我还发现:
到 2021 年,多项 Linux 内核改进(cgroups v2、psi、更好的页面写回限制)以及 systemd-oomd 已进入较新的发行版。
请注意,默认情况下不会利用许多 cgroup 资源控制改进和 systemd 对它的支持。对于桌面用例,它需要手动最终用户调整。
拥有全职开发团队的传统 Linux 发行版公司,例如 RedHat (CentOS/Fedora)、SUSE 或 Ubuntu (Debian),可能会将服务器端用例作为比桌面响应性更高的优先级。也许 Android 生态系统更可能将 Linux 拉向最终用户计算设备响应性需求,但鉴于 android 上使用的 init 不是 systemd,因此它不会有太大帮助,因此在内核之外,没有太多共享的好处。此外,为 Android 打包的内核可能以不同的方式配置和构建。
一些感兴趣的补丁:
因此,错误的不仅仅是用户空间代码和发行版配置/默认值的问题——旧内核可以更好地处理这个问题,而新内核可以,尽管内核 OOM 仍然不理想。
除了努力改进内核 OOM 之外,还有用户空间内存管理器开发与systemd-oomd. 不幸的是,Ubuntu 20.04 LTS 没有包含它,因为它们与旧版本的 systemd 一起发布。请参阅Systemd 247 合并 Systemd-OOMD 以改善低内存/内存不足处理。
- 禁用交换
建议至少提供一个小的交换分区(我们真的需要在现代系统上交换吗?)。禁用交换不仅可以防止换出未使用的页面,而且还可能影响内核用于分配内存的默认启发式过量使用策略(Overcommit_memory =0 中的启发式是什么意思?),因为该启发式确实依赖于交换页面。如果没有交换,过量使用仍然可以在启发式 (0) 或始终 (1) 模式下工作,但是不交换和从不 (2) 过量使用策略的组合可能是一个糟糕的主意。所以在大多数情况下,没有交换可能会损害性能。
例如,考虑一个长时间运行的进程,该进程最初为一次性工作接触内存,但随后未能释放该内存并继续运行后台。内核将不得不为此使用 RAM,直到进程结束。如果没有任何交换,内核就无法将其分页用于其他真正想要主动使用 RAM 的东西。还要考虑有多少开发人员是懒惰的,使用后没有明确释放内存。
- 设置最大内存 ulimit
它仅适用于每个进程,并且一个进程不应该请求系统物理上拥有的更多内存可能是一个合理的假设!因此,在仍然慷慨地设置的同时阻止一个单独的疯狂过程触发颠簸可能很有用。
- 将重要程序(X11、bash、kill、top 等)保存在内存中,永远不要交换它们
好主意,但是那些程序会占用它们不积极使用的内存。如果程序只请求适量的内存,这可能是可以接受的。
systemd 232 版本添加了一些使这成为可能的选项:我认为可以使用“MemorySwapMax=0”来防止像 ssh 这样的单元(服务)被换出任何内存。
尽管如此,能够优先考虑内存访问会更好。
交换抖动(当内存的工作集,即在给定的短时间内读取和写入的页面超过物理 RAM 时)将始终锁定存储 I/O - 没有内核魔法可以在不杀死进程的情况下拯救系统或两个...
希望在最近的内核中进行的 Linux 内核 OOM 调整能够识别工作集内存压力超过物理内存,在这种情况下,识别并杀死最合适的进程,即贪婪地使用最多内存的进程。“工作集”内存是进程依赖于频繁访问的活动/使用中的内存。
传统的内核OOM无法识别工作集超过物理内存(RAM)的情况,从而出现抖动问题。一个大的交换分区使问题变得更糟,因为它看起来好像系统仍然有虚拟内存空间,而内核愉快地提交并切断了更多的内存请求,但工作集可能会溢出到交换中,有效地尝试将存储视为好像这是内存。
在服务器上,内核 OOM 似乎接受了为确定的、缓慢的、不丢失数据的权衡而进行的性能损失。在台式机上,权衡是不同的,用户更喜欢丢失一些数据(进程牺牲)来保持响应。
这是关于 OOM 的一个很好的可笑类比:oom_pardon,又名不要杀死我的 xlock
顺便说一句,OOMScoreAdjust另一个系统选项可以帮助减轻和避免被认为更重要的 OOM 杀死进程。
OOMD,现在已经融入 systemd,因为 systemd-oomd 可以将这个问题从内核空间移到用户空间。
“使后台写回不那么糟糕”解释了 Linux“页面缓存”(块存储缓冲)在缓存被刷新到存储时如何导致一些问题。请求过多 RAM 的进程可能会迫使需要从页面缓存中释放内存,从而触发从内存到存储的大页面写回。无限制的回写会在 IO 上获得太多优先级,并导致其他进程的 IO 等待(阻塞)。如果内核耗尽了页面缓存以牺牲,换出其他进程内存(更多写入磁盘)将继续竞争 IO,继续 IO 争用并使其他进程无法访问存储。这不是导致颠簸问题本身的原因,但它确实加剧了响应能力的整体下降。
值得庆幸的是,对于较新的内核,block: hook up writeback throttling 应该限制页面缓存被写回存储的影响。我认为这也适用于后台进程内存换出到存储。
ulimits 的一个问题是会计限制适用于虚拟内存地址空间(这意味着结合物理和交换空间)。根据man limits.conf:
Run Code Online (Sandbox Code Playgroud)rss maximum resident set size (KB) (Ignored in Linux 2.4.30 and higher)
因此,将 ulimit 设置为仅适用于物理 RAM 使用似乎不再可用。因此
Run Code Online (Sandbox Code Playgroud)as address space limit (KB)
似乎是唯一受人尊敬的可调参数。
不幸的是,正如 WebKit/Gnome 示例所详细说明的那样,如果虚拟地址空间分配有限,某些应用程序将无法运行。
目前,这看起来很麻烦,但可以启用一些内核 cgroup 标志cgroup_enable=memory swapaccount=1(例如在 grub 配置中),然后尝试使用 cgroup 内存控制器来限制内存使用。
cgroups 具有比 'ulimit' 选项更高级的内存限制功能。CGroup v2注释暗示尝试改进 ulimits 的工作方式。
内存+交换计算和限制的组合被交换空间的真正控制所取代。
CGroup 选项可以通过systemd 资源控制选项设置。例如:
其他有用的选项可能是
这些有一些缺点:
在CGroup v2 中,他们建议这memory.high应该是一个很好的选择来限制和管理进程组的内存使用。然而,这句话来自 2015 年表明监控内存压力情况需要更多的工作:
内存压力的度量——工作负载因内存不足而受到的影响程度——对于确定工作负载是否需要更多内存是必要的;不幸的是,内存压力监控机制还没有实现。
2021年,工作似乎已经完成。请参阅 Facebook 做了一些工作和分析的参考资料:
鉴于 systemd 和 cgroup 用户空间工具很复杂,过去没有一种简单的方法来设置合适的东西,所以我没有进一步利用它。Ubuntu 的 cgroup 和 systemd 文档不是很好。
最后,较新的桌面版本可能会利用 cgroups 和 systemd-oomd,以便在高内存压力下,不会开始抖动。然而,未来可以做更多的工作来确保 ssh 和 X-Server/窗口管理器组件获得对 CPU、物理 RAM 和存储 IO 的更高优先级访问,并避免竞争不太重要的进程。内核的 CPU 和 I/O 优先级特性已经存在一段时间了。它似乎是缺乏对物理 RAM 的优先访问权,但现在已通过 cgroups v2 修复。
对于 Ubuntu 20.04,根本没有设置 CPU 和 IO 优先级。当我检查 systemd cgroup 限制、CPU 份额等时,据我所知,Ubuntu 16.04 和现在甚至 20.04 都没有包含任何预定义的优先级。例如我跑了:
systemctl show dev-mapper-Ubuntu\x2dswap.swap
Run Code Online (Sandbox Code Playgroud)
我将其与 ssh、samba、gdm 和 nginx 的相同输出进行了比较。如果发生颠簸,GUI 和远程管理控制台等重要内容必须与所有其他进程平等竞争。
我跑了:
grep -r MemoryMax /etc/systemd/system /usr/lib/systemd/system/
Run Code Online (Sandbox Code Playgroud)
并发现默认情况下没有单位对单位文件应用任何 MemoryMax 限制。所以默认情况下没有任何限制,系统管理员需要明确配置 systemd cgroup 内存限制配置。
我想启用休眠,所以我需要一个大的交换分区。因此尝试使用 ulimits 等进行缓解。
我输入* hard as 16777216了/etc/security/limits.d/mem.conf这样的内容:不允许单个进程请求比物理可能更多的内存。我不会阻止所有的颠簸,但如果没有,只有一个进程贪婪的内存使用或内存泄漏,就会导致颠簸。例如,我已经看到gnome-contacts在执行诸如从交换服务器更新全局地址列表之类的普通事情时会占用 8GB 以上的内存......
正如所见ulimit -S -v,许多发行版都将此硬限制和软限制设置为“无限制”,理论上,一个进程最终可能会请求大量内存,但只会主动使用一个子集,并且愉快地运行,认为它已获得 24GB 的 RAM 而系统只有16GB。当内核拒绝贪婪的推测内存请求时,上述硬限制将导致可能能够正常运行的进程中止。
但是,它还会捕获诸如 gnome 联系人之类的疯狂事情,而不是失去我的桌面响应能力,而是收到“可用内存不足”错误:
不幸的是,一些开发人员喜欢假装虚拟内存是一种无限资源,在虚拟内存上设置 ulimit 会破坏一些应用程序。例如,WebKit(一些 gnome 应用程序依赖它来集成 Web 内容)添加了一项gigacage安全功能,该功能会尝试分配大量的虚拟内存,并且会FATAL: Could not allocate gigacage memory发生带有厚颜无耻的提示的错误Make sure you have not set a virtual memory limit。解决办法,GIGACAGE_ENABLED=no放弃了安全优势,但同样,不允许限制虚拟内存分配也放弃了安全功能(例如可以防止拒绝服务的资源控制)。具有讽刺意味的是,在 gigacage 和 gnome 开发人员之间,他们似乎忘记了限制内存分配本身就是一种安全控制。可悲的是,我注意到依赖 gigacage 的 gnome 应用程序不会费心明确请求更高的限制,因此在这种情况下,即使是软限制也会破坏事情。根据Debian webkit-team NEWS:
如果基于 webkit 的应用程序的最大虚拟内存大小受到限制(例如使用 ulimit -v),则它们可能无法运行
公平地说,如果内核能够更好地基于常驻内存使用而不是虚拟内存来拒绝内存分配,那么假装虚拟内存是无限的就不那么危险了。
如果您希望应用程序被拒绝内存访问并希望停止过度使用,请使用以下命令来测试您的系统在高内存压力下的行为。
就我而言,默认提交比率是:
$ sysctl vm.overcommit_ratio
vm.overcommit_ratio = 50
Run Code Online (Sandbox Code Playgroud)
但它只有在更改策略以禁用过度使用并应用比率时才会完全生效
sudo sysctl -w vm.overcommit_memory=2
Run Code Online (Sandbox Code Playgroud)
该比率意味着总共只能分配 24GB 的内存(16GB RAM*0.5 + 16GB SWAP)。所以我可能永远不会看到 OOM 出现,并且实际上不太可能让进程不断访问交换中的内存。但我也可能会牺牲整体系统效率。
这将导致许多应用程序崩溃,因为开发人员通常无法优雅地处理拒绝内存分配请求的操作系统。它权衡了偶尔因颠簸(硬重置后丢失所有工作)导致的长时间锁定的风险与更频繁的各种应用程序崩溃的风险。在我的测试中,它没有多大帮助,因为当系统处于内存压力下并且无法分配内存时,桌面本身崩溃了。但是,至少控制台和 SSH 仍然有效。
VM 过量使用内存如何工作有更多信息。
sudo sysctl -w vm.overcommit_memory=0考虑到整个桌面图形堆栈及其中的应用程序仍然崩溃,我选择为此恢复默认设置。
| 归档时间: |
|
| 查看次数: |
30925 次 |
| 最近记录: |