在CentOS上如何导致malloc()返回NULL

4
我将要教授一门使用C语言的计算机科学导论课程,我想向学生展示为什么应该检查malloc()返回的值是否为NULL。我的计划是使用来限制可用内存量,以便我可以使用不同的限制条件测试不同的代码路径。我们规定的环境是CentOS 6.5。
我的第一次尝试失败了,命令行显示“Killed”。这使我发现了Linux OOM killer(内核调度器)。此后,我试图找出可以产生期望结果的一组神奇操作。显然,我需要处理以下内容:
/etc/sysctl.conf ulimit -m ulimit -v vm.overcommit_memory(根据Oracle文章,此值应设置为2)
到目前为止,我要么得到“Killed”,要么得到一个段错误,这两种情况都不是预期的结果。我的vm_overcommit_memory设置为2时会得到“Killed”,这意味着我肯定不理解发生了什么。
如果有人能找到一种人工且可靠地在CentOS上创建有限执行环境的方法,以便学生学习如何处理OOM和其他类型的错误,那么许多课程讲师将感激你。

3
void *mymalloc(size_t n) { return rand() % 3 ? malloc(n) : NULL; } 的意思是定义了一个名为 mymalloc 的函数,它接受一个大小为 n 的参数,并随机返回 malloc(n)NULL。而 #define malloc mymalloc 的作用是将标准库函数 malloc 替换成上述自定义的 mymalloc 函数。 - user529758
1
你尝试过在/etc/security/limits.conf中设置hard限制吗? - Elliott Frisch
1
@JasonFoster(只是提供信息,实际上,在Linux上malloc()几乎不会失败。几乎所有现代操作系统都会过度承诺内存,这意味着它们使malloc()返回一个非空指针,即使没有足够的内存,并且只有在那个指针被解除引用时才实际分配基础内存块。如果在此时分配失败,则会收到段错误或类似的错误提示。) - user529758
我没有找到limits.conf,但一些快速搜索似乎暗示它实际上是一个ulimit,而这似乎并没有起作用。最理想的解决方案是我可以实时更改而不必以不同用户身份登录。 - Jason Foster
@H2CO3 我在搜索中找到了那条消息,但我认为一定有办法让它发生。关于OOM Killer以及应该在服务器上禁用它的在线讨论足够多,因此我认为我的目标是可以实现的。我卡在Linux上,所以我希望(使用其他发布的语言)它可以被理性地处理。 - Jason Foster
显示剩余4条评论
1个回答

1

从内核版本2.5.30开始,可以有效地关闭过度承诺。

根据Linux内核内存

// 在此保存您的工作并记录当前的overcommit_ratio值

# echo 2 > overcommit_memory
# echo 1 > overcommit_ratio

这段文字的意思是将VM_OVERCOMMIT_MEMORY设置为2,表示不允许超过设置的overcommit_ratio值1(即不允许超额提交)。请注意保留HTML标记。

Null malloc demo

的意思是“空malloc演示”。
#include <stdio.h>
#include <stdlib.h>

int main(int argc,char *argv[])
{
  void *page = 0; int index;
  void *pages[256];
  index = 0;
  while(1)
  {
    page = malloc(1073741824); //1GB
    if(!page)break;
    pages[index] = page;
    ++index;
    if(index >= 256)break;
  }
  if(index >= 256)
  {
    printf("allocated 256 pages\n");
  }
  else
  {
    printf("memory failed at %d\n",index);
  }
  while(index > 0)
  {
    --index;
    free(pages[index]);
  }
  return 0;
}

输出

$ cat /proc/sys/vm/overcommit_memory 
0
$ cat /proc/sys/vm/overcommit_ratio 
50
$ ./code/stackoverflow/test-memory 
allocated 256 pages
$ su
# echo 2 > /proc/sys/vm/overcommit_memory 
# echo 1 > /proc/sys/vm/overcommit_ratio 
# exit
exit
$ cat /proc/sys/vm/overcommit_memory 
2
$ cat /proc/sys/vm/overcommit_ratio 
1
$ ./code/stackoverflow/test-memory 
memory failed at 0

记得将overcommit_memory恢复为0,overcommit_ratio按照说明进行调整。

你的解决方案已经帮我解决了大部分问题(谢谢!),但我有两个澄清问题。在应用虚拟机设置后,我尝试使用 ulimit -bulimit -m,但没有效果。但是 ulimit -v 做到了我想要的(即在工作状态和失败状态之间“切换”)。我不知道如何向学生(或者说自己)解释这一点。另一个问题是,我该如何计算(或确定)进程可用于 malloc() 的内存量?感谢您提供的出色答案和推动事情向前发展! - Jason Foster
ulimit -m 只会限制 RAM 内存,而不会限制您对 交换空间 的使用。 ulimit -v 限制了进程可用的虚拟内存(包括 _交换空间_)。可以尝试调整 调整您的交换空间大小 来确认这一概念。就进程可分配多少内存而言,您可以查看 ps v 的输出并在 %MEM 使用率上求和。 - amdixon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接