在什么情况下malloc可以返回NULL?

时间:2012-02-01 19:01:18

标签: c memory-management malloc

从来没有发生在我身上,而且我已经编程多年了。

有人能举例说明malloc实际上不起作用的非平凡程序吗?

我不是在谈论内存耗尽:我正在寻找一个简单的情况,当你只分配一个由用户给出的绑定大小的内存块时,假设一个整数,导致malloc失败。

10 个答案:

答案 0 :(得分:22)

你需要在嵌入式系统中做一些工作,你经常会在那里返回NULL: - )

在现代大容量地址空间和后备存储系统中耗尽内存要困难得多,但在处理大量数据的应用程序中,例如GIS或内存数据库,或在您的错误代码导致内存泄漏的地方。

但是,你以前从未体验过它并不重要 - 标准说它可能会发生,所以你应该迎合它。在过去的几十年里,我也没有被汽车击中,但这并不意味着我没有先看过去就在公路上徘徊。

重新编辑:

  

我不是在谈论内存耗尽,......

内存耗尽的定义malloc没有给你所需的空间。无论是分配所有可用内存还是堆碎片导致无法获得连续块,即使内存区域中所有空闲块的聚合更高,或者使用符合标准的功能人为限制地址空间使用也无关紧要:

void *malloc (size_t sz) { return NULL; }

C标准不区分失败的模式,只是成功或失败。

答案 1 :(得分:16)

尝试malloc比系统提供的内存更多(通过耗尽地址空间或虚拟内存 - 以较小者为准)。

malloc(SIZE_MAX)

可能会这样做。如果没有,重复几次直到你用完为止。

答案 2 :(得分:8)

任何用c编写的程序都需要动态分配比OS当前允许的内存更多的内存。

为了好玩,如果你在

中使用ubuntu类型
 ulimit -v 5000

您运行的任何程序很可能会崩溃(由于malloc失败),因为您已将任何一个进程的可用内存量限制为精简数量。

答案 3 :(得分:7)

除非您的内存已经完全保留(或严重分段),否则让malloc()返回NULL指针的唯一方法是请求大小为零的空间:

char *foo = malloc(0);

引用C99标准,§7.20.3,第1小节:

  

如果请求的空间大小为零,则行为是实现定义:返回空指针,或者行为就好像大小是某些   非零值,但返回的指针不得用于访问对象。

换句话说,malloc(0)可能会返回一个NULL指针或一个指向零分配字节的有效指针。

答案 4 :(得分:4)

只需查看malloc的手册页。

  

成功时,指向由函数分配的内存块的指针   此指针的类型始终为void *,可以将其强制转换为所需类型的数据指针,以便可以取消引用。
  如果函数未能分配所请求的内存块,则返回空指针。

答案 5 :(得分:3)

选择任何平台,虽然嵌入式可能更容易。 malloc(或new)一吨RAM(或随着时间的推移泄漏RAM,甚至使用朴素算法将其分段)。繁荣。当{"糟糕"}时,malloc确实会为我回复NULL事情正在发生。

回复您的编辑。是的,再次。随着时间的推移,内存碎片可能会使int的单个分配失败。另请注意,malloc不会为int分配4个字节,但可以获取所需的空间。它有自己的簿记功能,通常最少可以占用32-64字节。

答案 6 :(得分:3)

既然你问过一个例子,这里有一个程序(最终)会看到malloc返回NULL

perror();void*malloc();main(){for(;;)if(!malloc(999)){perror(0);return 0;}}

什么?你不喜欢故意混淆代码吗? ;)(如果它运行了几分钟并且没有在您的计算机上崩溃,请将其删除,将999更改为更大的数字然后重试。)

编辑:如果无论数字有多大都不起作用,那么正在发生的事情就是你的系统正在说“这里有一些记忆!”但只要你不尝试使用它,它就不会被分配。在这种情况下:

perror();char*p;void*malloc();main(){for(;;){p=malloc(999);if(p)*p=0;else{perror(0);return 0;}}

应该做的伎俩。如果我们可以使用GCC扩展,我认为我们可以通过将char*p;void*malloc();更改为void*p,*malloc();来缩小它,但如果您真的想要打高尔夫球,那么您将会使用Code Golf SE。

答案 7 :(得分:3)

在一个或多或少的标准系统上,使用标准的单参数malloc,有三种可能的失败模式(我能想到):

1)不允许分配请求的大小。例如,某些系统可能不允许分配> 16M,即使有更多存储空间。

2)所请求大小的连续空闲区域(默认边界)不能位于堆中。可能仍然有很多堆,但只是一块不够。

3)总分配堆超过了一些“人为”限制。例如,用户可能被禁止分配超过100M,即使有200M空闲且可用于单个组合堆中的“系统”。

(当然,你可以获得2和3的组合,因为有些系统会在增长时为堆分配非连续的地址空间块,将“堆大小限制”放在块的总数上。)< / p>

请注意,某些环境支持额外的malloc参数,例如对齐和池ID,这些参数可以添加自己的扭曲。

答案 8 :(得分:1)

是。当内核/系统lib确定无法分配内存时,Malloc将返回NULL。

您通常在现代机器上看不到这一点的原因是,Malloc并不真正分配内存,而是请求为您的程序保留一些“虚拟地址空间”,以便您可以在其中写入。像现代Linux这样的内核实际上过度提交,就是它们允许你分配比你的系统实际提供的内存更多的内存(swap + RAM),只要它们都适合系统的地址空间(通常是64位平台上的48位,IIRC) 。因此,在这些系统上,您可能会在触发返回NULL指针之前触发OOM杀手。一个很好的例子是32位机器中的512MB RAM:编写一个可被OOM杀手吃掉的C程序是微不足道的,因为它试图将所有可用的RAM +交换为malloc。

(在Linux上编译时可以禁用过度命令,因此它取决于构建选项,无论给定的Linux内核是否会过度使用。但是,库存桌面发行版内核会这样做。)

答案 9 :(得分:0)

当 malloc 参数为负数或 0 或堆上没有剩余内存时。 我不得不更正某人的代码,看起来像这样。

const int8_t bufferSize = 128;
void *buffer = malloc(bufferSize);

这里的buffer是NULL,因为bufferSize实际上是-128