如何优雅地解决这个内存问题?

如何优雅地解决这个内存问题?

我有一台标准的 Linux(Debian 测试)笔记本电脑,带有交换分区。

我用它做了很多实验。其中一些确实非常消耗内存,Linux 默认的行为方式对我来说是一个问题......让我们举一个愚蠢的例子:

  1. 坐在笔记本电脑前
  2. 打开终端
  3. 输入python,然后a = [0]*100000000

现在您很可能没有足够的 RAM 来处理这个大列表。 Linux 将填充 RAM,然后是交换区,几分钟后,OOM 杀手将被触发并杀死(几乎)随机服务,并且希望,如果您在适当的时候按下 Ctrl+C,python并且如果终端仍然有焦点,计算机将再次响应。

我想强制实施一些内存限制,以避免不必要的交换,并拒绝进程分配比我拥有的更多内存(RAM 中)的权利。如果内存需求低于某个限制或由 root 请求,则只需杀死除 root 之外的任何用户中最耗内存的进程。

ulimit -Sv [mem]我在后面听到了!

嗬嗬! “使用cgroups通过cgexec!”第一排有人说!

是的,你说得对:这些确实是非常好的解决方案。但:

  • 它们不适用于整个系统
  • 限制是按进程设置的
  • 限制是静态的,不考虑可用 RAM 的实际数量(AFAIK)
  • 这里那里,他们说这些并不是强制执行严格限制的真正好的解决方案。

我想要的是内核说:“你属于用户(不是root),你使用了大量内存,我们将耗尽内存。对不起,伙计……现在就去死吧!”

或者:“你到底在做什么?你需要XMB 并且只有yMB 可用。是的,SWAP 是空的,但是你不会打算用 SWAP 来做你的肮脏工作吧?不,我说不!没有你的记忆!你再坚持的话,你就死定了!”

答案1

有人在你耳边建议cgroups。好吧,尝试寻找那个方向,因为它可以为您提供:

  • 应用于您选择的一组任务(因此不是系统范围的,而是每个进程的)
  • 为该组设置了限制
  • 限制是静态的
  • 他们可以对内存和/或内存+交换强制实施硬限制

类似的东西可以给你带来更接近你的目标:

group limited {
  memory {
    memory.limit_in_bytes = 50M;
    memory.memsw.limit_in_bytes = 50M;
  }
}

这说明这个cgroup下的任务最多只能使用50M内存,50M内存+swap,所以当内存满时,不会交换,但如果内存未满,可以将一些数据映射到交换,这是可以允许的。

这是摘录自cgroup的内存文档:

通过使用memsw limit,您可以避免由于交换空间不足而导致的系统OOM。

答案2

我经常遇到同样的问题。我的一般工作流程涉及 MATLAB 中的大量计算。有时我会无意中尝试分配超出可用内存量的新变量。系统挂起,我通常必须硬重启机器才能恢复工作。 :P

就我而言,听起来也像你的情况一样,我不太关心将 MATLAB 使用的内存量限制为静态量 - 我对没有冻结的机器感兴趣,并且我愿意牺牲我的 MATLAB 进程以保持系统响应能力。

受到回应的启发这个帖子,我编写了以下脚本(我将其命名为watch_memory.sh):

#!/bin/bash

MONITOR=$(free | grep 'buffers/cache:')
MEM_USED=$(echo $MONITOR | awk '{ print $3 }')
MEM_FREE=$(echo $MONITOR | awk '{ print $4 }')

MEM_PERC=$(( 100*MEM_USED / (MEM_FREE+MEM_USED) ))

while :; do
    if [ "$MEM_PERC" -gt "95" ]
    then
        kill $1
        echo "$1 killed for using too much memory."
        exit
    fi
    sleep 1

    MONITOR=$(free | grep 'buffers/cache:')
    MEM_USED=$(echo $MONITOR | awk '{ print $3 }')
    MEM_FREE=$(echo $MONITOR | awk '{ print $4 }')
    MEM_PERC=$(( 100*MEM_USED / (MEM_FREE+MEM_USED) ))
done

该脚本每秒检查可用内存的百分比。当系统耗尽时,你的“替罪羊”pid(作为脚本的参数传递)就会被杀死。

在不调整脚本优先级(niceness)的情况下,替罪羊大约花了10-20秒才被杀死,但它仍然有效。以负优先级运行脚本会导致违规后立即终止(本例中的 11916 是我在内存不足时想要终止的 pid):

sudo nice -n -5 bash watch_memory.sh 11916

相关内容