如何限制进程及其子进程的总资源(内存)


16

关于约束单个进程的资源有很多问题和答案,例如RLIMIT_AS可用于约束由进程分配的最大内存,在诸如此类中可以视为VIRT top。有关该主题的更多信息,例如,这里是否有一种方法可以限制Unix中特定进程可以使用的内存量?

setrlimit(2) 文档说:

通过fork(2)创建的子进程继承其父级的资源限制。资源限制在execve(2)中保留。

应该通过以下方式理解:

如果某个进程的RLIMIT_AS为2GB,则它分配的内存不能超过2GB。当它产生一个子代时,会将2GB的地址空间限制传递给该子代,但计数从0开始。这两个进程加起来最多会占用4GB的内存。

但是,约束整个进程树分配的内存总和的有用方法是什么?



7
我来看看cgroups
slm

@slm谢谢!听起来像cgroups可以尝试。到目前为止,唯一可行的解​​决方案(使用丑陋的方法使用PS对内存求和并在超出限制时终止父进程)可能是使用某种形式的容器(lxc等)。
jpe 2014年

是的-我知道的工具并不会做一个小组,而只是一个进程,但是考虑到cgroups如何用于LXC和Docker等VM技术,我希望它能做您想要的事情。
slm

1
如果是Linux,则将父PID放在其自己的名称空间中,并以此方式控制它及其所有子对象。以下是对该概念的介绍性答案:unix.stackexchange.com/a/124194/52934
mikeserv 2014年

Answers:


8

我不确定这是否能回答您的问题,但是我发现这个perl脚本声称可以完全满足您的要求。该脚本通过唤醒并检查进程及其子进程的资源使用情况来实现自己的系统,以实施限制。它似乎已被很好地记录和解释,并且最近已更新。

正如slm在他的评论中所说,cgroups也可以用于此目的。假设您使用的是Linux,则可能必须安装用于管理cgroup的实用程序libcgroups

sudo cgcreate -t $USER:$USER -a $USER:$USER -g memory:myGroup

确保$USER是您的用户。

然后,您的用户应该可以访问中的cgroup内存设置/sys/fs/cgroup/memory/myGroup

然后,您可以通过以下方式将限制设置为500 MB:

echo 500000000 > /sys/fs/cgroup/memory/myGroup/memory.limit_in_bytes

现在运行Vim:

cgexec -g memory:myGroup vim

现在应该限制vim进程及其所有子进程只能使用500 MB的RAM。但是,我认为此限制仅适用于RAM而不适用于交换。一旦进程达到限制,它们将开始交换。我不确定是否可以解决此问题,我找不到使用cgroup限制交换使用的方法。


提出的解决方案确实可以限制进程树的常驻集大小。该行为似乎与RLIMIT_AS不同:可以分配比限制更多的内存,但是似乎无法实际使用更多的内存。
jpe 2014年

默认情况下,cgroup内存限制仅适用于(大约)物理RAM使用。有一个内核选项(CONFIG_MEMCG_SWAP)来启用交换记帐;有关详细信息,请参见内核文档
索伦Løvborg

1
sudo yum install libcgroup-tools
浅顶

2

我使用在Ubuntu中使用的cgmanager创建了执行此操作的脚本。一个优点是,这不需要root用户访问权限。请注意,cgroup管理是特定于发行版的,因此我不知道这是否适用于使用systemd cgroup管理的发行版。

#!/bin/sh

set -eu

if [ "$#" -lt 2 ]
then
    echo Usage: `basename $0` "<limit> <command>..."
    exit 1
fi

limit="$1"
shift
cgname="limitmem_$$"
echo "limiting memory to $limit (cgroup $cgname) for command $@"

cgm create memory "$cgname" >/dev/null
cgm setvalue memory "$cgname" memory.limit_in_bytes "$limit" >/dev/null
# try also limiting swap usage, but this fails if the system has no swap
cgm setvalue memory "$cgname" memsw.limit_in_bytes "$limit" >/dev/null 2>&1 || true

# spawn subshell to run in the cgroup
set +e
(
set -e
cgm movepid memory "$cgname" `sh -c 'echo $PPID'` > /dev/null
exec "$@"
)
# grab exit code
exitcode=`echo $?`

set -e

echo -n "peak memory used: "
cgm getvalue memory "$cgname" memory.max_usage_in_bytes | tail -1 | cut -f2 -d\"

cgm remove memory "$cgname" >/dev/null
exit $exitcode

用法:另存为limitmem您的路径并使其可执行。然后运行例如limitmem 1G command...。这限制了实际使用的内存。如果达到该目标,OOM杀手将杀死该进程或其子进程,但不会杀死与此命令无关的随机变量。


感谢您的简短cgm指南,它很有用
Vitaly Isaev

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.