我如何快速停止导致崩溃的进程(由于过多的内存分配)?


19

我们都经历过-要求某些程序执行需要大量内存的操作。它会尽职地尝试分配所有这些内存,然后系统立即开始崩溃,不断交换并变得迟钝或无响应。

我最近在我的Ubuntu笔记本电脑上遇到了这种情况,这是因为Matlab脚本试图分配一个可笑的巨大矩阵。经过大约5分钟以上的重击后,我能够按Ctrl-F1进入控制台并杀死Matlab。我宁愿有一些热键,可以立即让我控制系统,并让我杀死令人讨厌的过程;或者,也许只是默默地拒绝分配这么大的缓冲区。

  1. 重新获得对Linux系统的控制的最快方法是什么,该Linux系统由于过度交换而变得无响应或极其缓慢。

  2. 是否有一种有效的方法来防止这种交换首先发生,例如通过限制允许进程尝试分配的内存量?

Answers:


12

Alt-SysRq-F使用最多的内存来终止进程:

  • SysRq键通常映射到Print键。
  • 如果您使用的是图形桌面,则可能需要按Ctrl-Alt-SysRq-F,以防按Alt-SysRq触发其他操作(例如,快照程序)。
  • 如果您使用的是笔记本电脑,则可能还需要按功能键。
  • 有关更多信息,请阅读Wikipedia文章

5

我为此编写了一个脚本-https: //github.com/tobixen/thrash-protect

我已经在生产服务器,工作站和便携式计算机上成功运行了此脚本。该脚本不会杀死进程,但会暂时将其挂起-后来我有几种情况,我确定如果不是这个简单的脚本,我会因为失败而失去控制。在“最糟糕”的情况下,违规过程将大大减慢速度,最终被内核(OOM)杀死,在“最佳”情况下,违规过程实际上将完成...无论如何,服务器或工作站会保持相对敏感,以便轻松调查情况。

当然,“购买更多的内存”或“不使用交换”是关于“如何避免rash动?”问题的两个替代的,更传统的答案,但总的来说,它们的效果不太好(安装更多的内存可能毫无疑问,一个无赖进程可以吞噬所有内存,无论已安装了多少内存,并且如果没有足够的内存来缓冲/缓存,即使没有交换也可以陷入崩溃问题)。我确实建议使用防摔保护以及大量交换空间。


根据unix.stackexchange.com/a/24646/9108,关于禁用交换,它可能不是最佳选择。
sashoalm

确实,有人对我发表了同样的评论,因此我当时修改了Thrash-protect文档。
tobixen

4
  1. 重新获得对Linux系统的控制的最快方法是什么,该Linux系统由于过度交换而变得无响应或极其缓慢。

上面已经用Alt-SysRq-F回答了

  1. 是否有一种有效的方法来防止这种交换首先发生,例如通过限制允许进程尝试分配的内存量?

我正在回答第二部分。是的,ulimit仍然可以很好地限制单个进程。您可以:

  • 为您知道可能会失控的流程设置软限制
  • 如果您想要额外的保险,请为所有流程设定硬性限制

另外,如前所述:

您可以使用CGroups限制资源使用并防止此类问题

确实,cgroup提供了更高级的控制,但我认为当前配置更为复杂。

老学校限制

一旦脱落

这是一个简单的例子:

$ bash
$ ulimit -S -v $((1*2**20))
$ r2(){r2 $@$@;};r2 r2
bash: xmalloc: .././subst.c:3550: cannot allocate 134217729 bytes (946343936 bytes allocated)

它:

  • 设置总内存使用量为1GB的软限制(ulimit假定限制以kB为单位)
  • 运行一个递归bash函数调用r2(){ r2 $@$@;};r2 r2,该函数将通过在请求堆栈内存时将自身无限加倍来成倍地消耗CPU和RAM。

如您所见,当尝试请求超过1GB时,它停止了。

注意,-v对虚拟内存分配(总计,即物理+交换)进行操作。

永久保护

要限制虚拟内存分配,as等效于-vfor limits.conf

我执行以下操作以防止任何单个的异常行为:

  • 为所有进程设置硬地址空间限制。
  • address space limit = <physical memory> - 256MB
  • 因此,没有使用贪婪内存或活动循环和内存泄漏的单个进程可以消耗所有物理内存。
  • 256MB的可用空间可用于使用ssh或控制台进行必要的处理。

一班轮:

$ sudo bash -c "echo -e \"*\thard\tas\t$(($(grep -E 'MemTotal' /proc/meminfo | grep -oP '(?<=\s)\d+(?=\skB$)') - 256*2**10))\" > /etc/security/limits.d/mem.conf"

作为验证,将得到以下结果(例如,在16GB系统上):

$ cat /etc/security/limits.d/mem.conf
*   hard    as      16135196
$ ulimit -H -v
161351960

笔记:

  • 仅缓解单个进程过度占用内存的情况。
  • 不能防止内存压力大的多进程工作负载导致崩溃(然后是cgroups)。
  • 不要rss在limits.conf中使用选项。较新的内核不尊重它。
  • 很保守
    • 从理论上讲,进程可以推测性地请求大量内存,但只能主动使用子集(较小的工作集/驻留内存使用量)。
    • 上面的硬限制将导致此类进程中止(即使它们可能在其他情况下也可以正常运行,因为Linux允许虚拟内存地址空间被过量使用)。

较新的CGroups

提供更多控制权,但当前使用起来更加复杂:

  • 改进了ulimit产品。
    • memory.max_usage_in_bytes 可以分别说明和限制物理内存。
    • 尽管ulimit -m和/或rssin limits.conf旨在提供类似的功能,但是自内核Linux 2.4.30起该功能不起作用!
  • 需要在引导加载程序中启用一些内核cgroup标志:cgroup_enable=memory swapaccount=1
    • 在Ubuntu 16.04中,默认情况下不会发生这种情况。
    • 可能是由于额外记帐开销对性能的某些影响。
  • cgroup / systemd的东西是相对较新的,并且发生了一些变化,因此上游的变化意味着Linux发行版供应商尚未使它易于使用。在14.04LTS和16.04LTS之间,使用cgroup的用户空间工具已更改。
    • cgm 现在似乎是官方支持的用户空间工具。
    • systemd单元文件似乎还没有任何预定义的“供应商/发行版”默认值来优先处理ssh之类的重要服务。

例如,检查当前设置:

$ echo $(($(cat /sys/fs/cgroup/memory/memory.max_usage_in_bytes) / 2**20)) MB
11389 MB
$ cat /sys/fs/cgroup/memory/memory.stat
...

例如,限制单个进程的内存:

$ cgm create memory mem_1G
$ cgm setvalue memory mem_1G memory.limit_in_bytes $((1*2**30))
$ cgm setvalue memory mem_1G memory.memsw.limit_in_bytes $((1*2**30))
$ bash
$ cgm movepid memory mem_1G $$
$ r2(){ r2 $@$@;};r2 r2
Killed

要查看它的运行情况,将其作为后台进程消耗掉RAM,然后被杀死:

$ bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2' & while [ -e /proc/$! ]; do ps -p $! -o pcpu,pmem,rss h; sleep 1; done
[1] 3201
 0.0  0.0  2876
 102  0.2 44056
 103  0.5 85024
 103  1.0 166944
 ...
98.9  5.6 920552
99.1  4.3 718196
[1]+  Killed                  bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2'

注意内存请求的指数增长(2的幂)。

将来,我们希望看到“发行版/供应商”为SSH和图形堆栈等重要内容预先配置cgroup优先级和限制(通过系统单元),以使它们永远不会挨饿。


2

您可能可以按Ctrl- z暂停程序。然后,您可以执行操作kill %1(或任何作业编号,也可以使用PID)。

您可以使用ulimit命令尝试限制进程可用的内存量。


Ctrl-Z很好,但是通常我运行的是Matlab GUI,并且失去了对控制终端的跟踪,因此没有简单的方法来发布Ctrl-Z按键。如果GUI具有热键将SIGSTOP发送到任何具有焦点的应用程序,那就太好了!
nibot 2011年

您可以运行kill -STOP <pid>与Ctrl-Z相同的功能。
hlovdal11年

是的,但是整个问题是,在这种情况下,系统反应迟钝,以至于需要很长时间(或永远)才能到达命令提示符。
nibot 2011年

1

您可以使用CGroups限制资源使用并防止此类问题:https ://en.wikipedia.org/wiki/Cgroups


请在回答中包括必要的信息,并使用该链接进行归因和进一步阅读。该链接描述了CGroups是什么,但是从该链接来看如何实际使用CGroups来解决问题并不明显。您可以扩展答案来描述问题的解决方案吗?谢谢。
fixer1234

0

如果GUI具有热键将SIGSTOP发送到任何具有焦点的应用程序,那就太好了!

总是有经典xkill命令(在我的系统上,来自xorg-x11-apps-7.4-14.fc14.src.rpm)。我想做一个发送SIGSTOP的克隆而不是杀死目标窗口应该不是很困难。


按下某个组合键,如何使xkill快速启动?
nibot 2011年

我不确定。我假设gnome和KDE都具有一些可用于启动程序的全局快捷方式功能。
hlovdal
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.