在Linux上防止内存不足(OOM)冻结的最佳方法是什么?

时间:2010-01-24 03:37:36

标签: linux memory linux-kernel out-of-memory

有没有办法让OOM杀手工作并阻止Linux冻结?我一直在运行Java和C#应用程序,其中通常使用分配的任何内存,并且(如果我正确理解它们)过度使用会导致计算机冻结。现在,作为临时解决方案,我补充道,

vm.overcommit_memory = 2
vm.overcommit_ratio = 10

到/etc/sysctl.conf。

对任何能够解释为什么现有的OOM杀手无法以保证方式正常运行的人都会感到荣幸,只要内核耗尽“真实”内存,就会终止进程。

编辑 - 很多回应都与迈克尔有关“如果你遇到与OOM杀手相关的问题,那么你可能需要修复导致你内存不足的任何问题”。我不认为这是正确的解决方案。总会有应用程序出现错误,我想调整内核,这样我的整个系统就不会冻结。鉴于我目前的技术理解,这似乎不应该是不可能的。

6 个答案:

答案 0 :(得分:3)

下面是我写的一个非常基本的perl脚本。通过一些调整,它可能是有用的。您只需要将路径更改为使用Java或C#的任何进程的路径。您可以更改我用于重启命令的kill命令。 当然为了避免手动输入perl memusage.pl,您可以将其放入crontab文件中以自动运行。您也可以使用perl memusage.pl> log.txt将其输出保存到日志文件中。对不起,如果它没有真正的帮助,但我喝一杯咖啡时很无聊。 :-D干杯

#!/usr/bin/perl -w
# Checks available memory usage and calculates size in MB
# If free memory is below your minimum level specified, then
# the script will attempt to close the troublesome processes down
# that you specify. If it can't, it will issue a -9 KILL signal.
#
# Uses external commands (cat and pidof)
#
# Cheers, insertable

our $memmin = 50;
our @procs = qw(/usr/bin/firefox /usr/local/sbin/apache2);

sub killProcs
{
    use vars qw(@procs);
    my @pids = ();
    foreach $proc (@procs)
    {
        my $filename=substr($proc, rindex($proc,"/")+1,length($proc)-rindex($proc,"/")-1);
        my $pid = `pidof $filename`;
        chop($pid);
        my @pid = split(/ /,$pid);
        push @pids, $pid[0];
    }
    foreach $pid (@pids)
    {
        #try to kill process normall first
        system("kill -15 " . $pid); 
        print "Killing " . $pid . "\n";
        sleep 1;
        if (-e "/proc/$pid")
        {
            print $pid . " is still alive! Issuing a -9 KILL...\n";
            system("kill -9 " + $pid);
            print "Done.\n";
        } else {
            print "Looks like " . $pid . " is dead\n";
        }
    }
    print "Successfully finished destroying memory-hogging processes!\n";
    exit(0);
}

sub checkMem
{
    use vars qw($memmin);
    my ($free) = $_[0];
    if ($free > $memmin)
    {
        print "Memory usage is OK\n";
        exit(0);
    } else {
        killProcs();
    }
}

sub main
{
    my $meminfo = `cat /proc/meminfo`;
    chop($meminfo);
    my @meminfo = split(/\n/,$meminfo);
    foreach my $line (@meminfo)
    {
        if ($line =~ /^MemFree:\s+(.+)\skB$/)
        {
            my $free = ($1 / 1024);
            &checkMem($free);
        }
    }
}

main();

答案 1 :(得分:1)

如果您的进程的oom_adj设置为-17,则不会考虑杀死,尽管我怀疑这是问题所在。

cat /proc/<pid>/oom_adj

将告诉您进程的值oom_adj。

答案 2 :(得分:0)

我编写了一个简单的脚本,用于在发布时设置 OOM 分数。所有子进程都会继承这个分数。

#!/usr/bin/env sh

if [ -z "$1" ] || [ -z "$2" ]; then
  echo "Usage: $(basename "$0") oom_score_adj command [args]..."
  echo "  oom_score_adj  A score between -1000 and 1000, bigger gets killed first"
  echo "  command        The command to run"
  echo "  [args]         Optional args for the command to run"
  exit 1
fi

set -eux

echo $1 > /proc/self/oom_score_adj
shift
exec $@

脚本将本地进程的分数设置为提供的第一个参数。这可以是 -1000 到 1000 之间的任何值,其中 1000 最有可能首先被杀死。然后将其余参数作为带有 args 的命令执行,替换当前进程。

答案 3 :(得分:-1)

我不得不说防止OOM冻结的最好方法是不要耗尽虚拟内存。如果你经常耗尽虚拟内存或接近虚拟内存,那么你就会遇到更大的问题。

大多数任务都不能很好地处理失败的内存分配,因此容易崩溃或丢失数据。耗尽虚拟内存(使用或不使用overcommit)将导致某些分配失败。这通常很糟糕。

此外,在你的操作系统耗尽虚拟内存之前,它会开始做坏事,比如从常用的共享库中丢弃页面,这可能会让性能变得很糟糕,因为它们必须经常被拉回来,这非常糟糕对于吞吐量。

我的建议:

  • 获取更多ram
  • 运行更少的流程
  • 使您运行的进程使用更少的内存(这可能包括修复内存泄漏)

也可能

  • 设置更多交换空间

如果这对您的用例有帮助。

大多数多进程服务器运行可配置(最大)数量的进程,因此您通常可以向下调整它。多线程服务器通常允许您在内部配置用于缓冲区等的内存量。

答案 4 :(得分:-1)

首先,你怎么能确定冻结与OOM杀手有关?我在现场有一个系统网络,我不会经常冻结,这似乎与OOM无关(我们的应用在内存使用方面非常稳定)。它可能是别的吗?有没有涉及有趣的硬件?有不稳定的司机?高性能视频?

即使OOM杀手参与并且工作,你仍然会有问题,因为你认为正在运行的东西现在已经死了,谁知道它留下了什么样的混乱。

真的,如果您遇到与OOM杀手相关的问题,那么您可能需要修复导致内存不足的任何问题。

答案 5 :(得分:-1)

我发现修复稳定性问题主要依赖于准确识别根本原因。不幸的是,这需要能够看到问题发生时发生的事情,这是尝试启动各种监控程序的非常糟糕的时间。

我有时觉得有用的一件事是在启动时启动一个小的监控脚本,它会记录各种有趣的数字并快照正在运行的进程。然后,如果发生崩溃,我可以在崩溃前查看情况。我有时发现直觉对根本原因是非常错误的。不幸的是,那个脚本已经过时了,或者我给了一个链接。