如果一个进程超过了给定的内存限制,自动终止该进程。

我处理大规模数据集。在测试新软件时,有时会出现一个脚本,它会突然占用所有可用的内存,使我的桌面无法使用。我希望能够设置一个进程的内存限制,如果超过这个限制,它将被自动终止。语言特定的解决方案可能行不通,因为我使用各种不同的工具(R、Perl、Python、Bash等)。
所以,是否有一种进程监视器可以让我设置一个内存阈值,并在使用超过该阈值时自动终止进程?

http://askubuntu.com/questions/54202/can-i-automatically-kill-any-application-that-uses-more-than-a-certain-percentage - Uri Herrera
@ Uri:在那个帖子里,我只得到了一个部分(只回答了我的问题中关于CPU的部分)而且并不是最佳的答案。 他问的是关于内存使用情况。 - Chriskin
1Uri,那个主题中完全缺乏有用的想法。发布链接并没有什么特别有帮助。 - chrisamiller
1嗯 - 这个超级用户的帖子似乎有一个合理的建议,使用ulimit:http://superuser.com/questions/66383/restrict-ram-for-user-or-process - chrisamiller
4个回答

我强烈建议不要这样做。正如@chrisamiller所建议的,设置ulimit将限制进程可用的RAM。
但是如果你坚持要做,那么请按照以下步骤进行。
将以下脚本保存为killif.sh
```sh #!/bin/sh
if [ $# -ne 2 ]; then echo "参数数量无效" exit 0 fi
while true; do SIZE=$(pmap $1|grep total|grep -o "[0-9]*") SIZE=${SIZE%%K*} SIZEMB=$((SIZE/1024)) echo "进程ID =$1 大小 = $SIZEMB MB" if [ $SIZEMB -gt $2 ]; then printf "大小已超过。\n正在终止进程......" kill -9 "$1" echo "已终止进程" exit 0 else echo "大小尚未超过" fi
sleep 10 done ```
现在使其可执行。
```shell chmod +x killif.sh ```
现在在终端上运行此脚本。用实际的进程ID替换PROCID,用以MB为单位的大小替换SIZE
例如:
```shell ./killif.sh 132451 100 ```
如果SIZE为100,则当进程的RAM使用量超过100 MB时,进程将被终止。
注意:你知道自己想要做什么。终止进程并不是一个好主意。如果该进程有任何关机或停止命令,请编辑脚本,并用该命令替换kill -9命令。

我会考虑在那里放置少量的睡眠,例如0.5小时的睡眠。 - Denwerko
@George Edison 你是怎么做到的?当我尝试粘贴时,它给我奇怪格式的文本。 Denwerko:你想把sleep放在哪里?我已经在while循环中设置了10秒的sleep。 - Amey Jah
2感谢您提供的解决方案,如下所注意,我会进行查看。不过为何要发出如此严厉的关于终止进程的警告呢?集群管理软件(LSF、PBS等)经常在进程超出请求的资源限制时执行此操作,并没有造成严重后果。我同意对于可能错误使用这一方法的新用户来说,这并非一个好的解决方案,但在适当的情况下,它确实能够非常有用。 - chrisamiller
@chrisamiller 我已经为未来的读者发布了一个警告。在你的情况下,你知道这些影响,但是未来阅读此帖子的人可能不清楚这些影响。 - Amey Jah
@Amey:你只需要在每行前面插入4个空格。由于你使用了项目符号,所以你需要在每行前面插入8个空格。 - Nathan Osman
2你能详细说明一下为什么不要这样做吗? - jterm

我不喜欢回答自己的问题,但今天早上我找到了一种替代方法,这是一个很好的小工具。它可以限制CPU时间或内存消耗。

https://github.com/pshved/timeout

我先试试这个,但是点赞给Amey Jah的好答案。如果这个不行,我会去看看他的回答。

5回答自己的问题是可以的!请参考这篇博文 - Tom Brossman

这个内容太长无法放入评论。我修改了Amey的原始脚本,添加了一个pgrep,所以不需要手动输入进程ID,你只需要通过名称排除即可。例如,./killIf.sh chrome 4000会终止任何内存使用超过4GB的chrome进程。

#!/bin/sh

# $1 is process name
# $2 is memory limit in MB

if [ $# -ne 2 ];
then
    echo "Invalid number of arguments"
    exit 0
fi

while true;
do
    pgrep "$1" | while read -r procId;
    do
        SIZE=$(pmap $procId | grep total | grep -o "[0-9]*")
        SIZE=${SIZE%%K*}
        SIZEMB=$((SIZE/1024))
        echo "Process id = $procId Size = $SIZEMB MB"
        if [ $SIZEMB -gt $2 ]; then
            printf "SIZE has exceeded.\nKilling the process......"
            kill -9 "$procId"
            echo "Killed the process"
            exit 0
        else
            echo "SIZE has not yet exceeding"
        fi
    done

    sleep 1
done

小心选择一个狭窄的grep字符串和足够大的内存限制,以免不必要地终止意外的进程。

完美运作。有助于控制那个永远泄漏内存的Telegram桌面应用程序。 - Mirror Mirage
我可以提出一个改进建议 - 允许指定多个进程,创建一个数组并循环遍历它们。 - Martin Zeltin

尝试使用prlimit工具,它来自于util-linux软件包。它可以在程序中设置资源限制。它使用prlimit系统调用来设置这些限制,并由内核纯粹地执行。

您可以配置16个限制,包括:

  • 以秒为单位的最大CPU时间
  • 最大用户进程数
  • 最大驻留集大小(即"已使用内存")
  • 进程可锁定到内存中的最大大小
  • 虚拟内存大小
  • 最大打开文件数
  • 最大文件锁数
  • 最大待处理信号数
  • POSIX消息队列中的最大字节数