2016-12-04 49 views
0

这段代码使用了一些在命令行输入和调用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”返回之前冻结系统几分钟,然后系统在几分钟内保持缓慢。

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

+1

'malloc'不成功时返回'NULL'。请检查,这是至关重要的。 –

+2

Linux内核允许内存过度提交(以便允许程序请求比可用内存更多的内存,并且分配成功,但当内存不可用时代码崩溃)。在您最喜爱的搜索引擎上搜索“Linux OOM Killer”(内存不足杀手)。你的代码并不真正使用它正在分配的内存;需要很长时间才能用完,因为您必须耗尽指针的空间,而不是内存本身。如果你在分配它之后清零内存(也许使用'calloc()'),你会更快崩溃,并且对系统的影响更小。 –

+0

当流程实际需要大量内存时,您认为应该发生什么?无论如何它应该被杀害? – immibis

回答

1

为什么OS允许一个进程接管内存到这样的程度?

因为它被配置为这样。

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

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

问题是,这些限制是非常特定于任务的。它们从系统到系统甚至从用户到用户都有很大差异:有些人不喜欢他们的系统开始分页(像OP描述的那样放慢速度),宁愿进程失败;其他人则更愿意等待一段时间,因为他们实际上需要从资源匮乏的过程中获得结果。设置限制是系统管理员的责任。

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

#!/bin/sh 
exec prlimit --as=1073741824 --rss=262144 "[email protected]" 

,您可以与地址空间中运行任何你的程序的限制为1块GB和驻留集大小(实际使用的内存量)256K页面。