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



这从未发生在我身上,我已经编程多年了。

有人能给我举一个malloc实际上不起作用的非平凡程序的例子吗?

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

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

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

但你是否从未经历过这种情况并不重要——标准上说它可能发生,所以你应该迎合它。在过去的几十年里,我也没有被车撞过,但这并不意味着我在马路上闲逛时没有先看一眼。

然后重新编辑:

我不是在说记忆力衰竭。。。

内存耗尽的定义就是CCD_ 3没有给你想要的空间。这是由分配所有可用内存引起的,还是由堆碎片引起的,这意味着即使内存领域中所有可用块的总和更高,你也无法获得连续块,或者是人为限制你的地址空间使用,例如使用符合标准的函数:

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

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

是。

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

malloc(SIZE_MAX)

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

任何用c编写的程序,需要动态分配比操作系统当前允许的更多的内存。

有趣的是,如果你在中使用ubuntu类型

 ulimit -v 5000

您运行的任何程序都很可能崩溃(由于malloc故障),因为您已将任何一个进程的可用内存量限制在一个简洁的数量。

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

char *foo = malloc(0);

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

如果请求的空间大小为零,则行为被定义为:返回一个空指针,或者行为就像大小为非零值,除非返回的指针不应用于访问对象。

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

选择任何平台,尽管嵌入式可能更容易。malloc(或new)一吨RAM(或随着时间的推移泄漏RAM,甚至通过使用幼稚算法将其分段)。繁荣malloc确实会在发生"不好"的事情时为我返回NULL

响应您的编辑。是的。随着时间的推移,内存碎片可能会导致int的单个分配失败。还要记住,malloc不仅为int分配4个字节,而且可以随心所欲地占用空间。它有自己的记账功能,通常会占用32-64字节的最小值。

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

  1. 不允许请求的分配大小。例如,一些系统可能不允许分配>1600万,即使有更多的存储空间。

  2. 堆中无法找到具有默认边界的请求大小的连续可用区域。可能还有很多堆,但只是不够完整。

  3. 所分配的总堆已经超过了一些";人造的";限度例如,用户可能被禁止分配超过100M,即使有200M空闲并且可用于";系统";在单个组合堆中。

(当然,你可以得到2和3的组合,因为有些系统会随着堆的增长向堆分配不连续的地址空间块,从而对块的总数设置"堆大小限制"。)

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

只需查看malloc的手册页面。

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

是。当内核/系统库确定不能分配内存时,Malloc将返回NULL。

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

(在Linux上,过度调试可以在编译时禁用,因此取决于构建选项给定的Linux内核是否会过度调试。但是,普通的桌面发行版内核会这样做。)

既然你问了一个例子,这里有一个程序将(最终)看到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();来获得更小的扩展,但如果你真的想打高尔夫球,那么当malloc参数为负数或0,或者堆上没有内存时,你应该使用Code golf SE.

。我必须纠正某人的代码,它看起来像这样。

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

这里的缓冲区为NULL,因为bufferSize实际上是-128

最新更新