【问题标题】:Why is heap overflow "allowed" to freeze the system?为什么堆溢出“允许”冻结系统?
【发布时间】:2017-04-19 04:48:55
【问题描述】:

此代码在命令行中将一个数字作为输入,并多次调用 heapOverflow() 函数:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void heapOverflow()
{
    unsigned *some_array = malloc(50000);
}

int main(int argc, char *argv[])
{
    unsigned num_calls = atoi(argv[1]);

    while (num_calls > 0)
    {
        heapOverflow();
        num_calls--;
    }

    return 0;
}

在 Linux Mint 17.1 上,使用足够大的输入(例如,在我的情况下为 10000000)运行此程序会使系统冻结几分钟,然后 bash 返回“Killed”,然后系统再缓慢运行几分钟。

为什么操作系统允许进程在这种程度上接管内存?当很明显它会请求太多堆内存时,调度程序和内存管理器不应该一起工作来杀死一个进程吗?或者是否存在将所有这些内存分配给一个进程可能有用的情况(即,即使系统的其余部分或至少 X GUI 系统被冻结,该进程实际上是否可以做有用的工作?)

【问题讨论】:

  • malloc 不成功时返回NULL。请检查,这是必不可少的。
  • Linux内核允许内存过度提交(这样程序就可以请求比可用内存更多的内存,并且分配成功,但是当内存根本不可用时代码会崩溃) .在您最喜欢的搜索引擎上搜索“Linux OOM Killer”(内存不足杀手)。您的代码并没有真正使用它分配的内存;它需要很长时间才能用完,因为您必须用完指针的空间,而不是内存本身。如果您在分配内存后将其归零(可能使用calloc()),您会更快崩溃,并且对系统的影响更小。
  • 当一个进程实际上需要大量内存时,您认为应该发生什么?无论如何都应该被杀死吗?
  • @immibis 是的,我想我错误地将操作系统和发行版软件混为一谈。内核是否不需要关心进程的相对重要性,并且它“信任”程序员选择如何最好地使用内存?
  • @JonathanLeffler 感谢您的详细回答和参考!

标签: c linux memory-management operating-system heap-memory


【解决方案1】:

为什么操作系统允许进程在这种程度上接管内存?

因为它被配置为这样做。

除其他功能外,Linux 内核还支持POSIX.1-2008 中标准化的每进程资源限制;参见例如prlimit 用于命令行访问这些,getrlimit()/setrlimit() 用于 C 库接口。

在大多数 Linux 发行版中,这些限制由 limits.conf 中的可插入身份验证模块 pam_limits 设置。

问题是,这些限制是针对特定任务的。它们因系统而异,甚至因用户而异:有些人不喜欢他们的系统开始分页(像 OP 描述的那样变慢),宁愿进程失败;其他人更愿意等待一段时间,因为他们实际上需要资源匮乏过程的结果。设置限制是系统管理员的责任。

我想人们可以很容易地编写一个程序来检查当前配置(特别是/proc/meminfo),并为单用户台式机/笔记本电脑设置资源限制。但是,您也可以创建一个帮助脚本,例如 /usr/local/bin/run-limited

#!/bin/sh
exec prlimit --as=1073741824 --rss=262144 "$@"

因此您可以运行任何程序,地址空间限制为 1 GB,驻留集大小(实际使用的 RAM 量)为 256k 页。

【讨论】:

    猜你喜欢
    • 2020-01-06
    • 2012-05-10
    • 2010-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-03
    • 2017-09-09
    • 2021-06-18
    相关资源
    最近更新 更多