- 重新获得对Linux系统的控制的最快方法是什么,该Linux系统由于过度交换而变得无响应或极其缓慢。
上面已经用Alt-SysRq-F回答了
- 是否有一种有效的方法来防止这种交换首先发生,例如通过限制允许进程尝试分配的内存量?
我正在回答第二部分。是的,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
等效于-v
for 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
和/或rss
in 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优先级和限制(通过系统单元),以使它们永远不会挨饿。