It has never happened to me, and I've programming for years now.
我从来没有遇到过这种情况,我已经编程多年了。
Can someone give me an example of a non-trivial program in which malloc
will actually not work?
有人能给我举一个非平凡项目的例子吗? malloc实际上不能工作?
I'm not talking about memory exhaustion: I'm looking for the simple case when you are allocating just one memory block in a bound size given by the user, lets say an integer, causes malloc
to fail.
我不是在讨论内存耗尽:我是在寻找一个简单的情况,当您在用户给定的绑定大小中只分配一个内存块时,比如一个整数,会导致malloc失败。
9 个解决方案
#1
14
Yes.
是的。
Just try to malloc
more memory than your system can provide (either by exhausting your address space, or virtual memory - whichever is smaller).
只要尝试malloc比您的系统提供更多的内存(通过耗尽您的地址空间,或者虚拟内存——无论哪个更小)。
malloc(SIZE_MAX)
will probably do it. If not, repeat a few times until you run out.
可能会这样做。如果没有,重复几次,直到用完。
#2
20
You need to do some work in embedded systems, you'll frequently get NULL returned there :-)
您需要在嵌入式系统中做一些工作,您将经常得到空返回:-)
It's much harder to run out of memory in modern massive-address-space-and-backing-store systems but still quite possible in applcations where you process large amounts of data, such as GIS or in-memory databases, or in places where your buggy code results in a memory leak.
在现代的大型地址空间和备份存储系统中,内存耗尽要难得多,但在处理大量数据(如GIS或内存中的数据库)的应用程序中,或者在错误代码导致内存泄漏的地方,内存耗尽仍然是可能的。
But it really doesn't matter whether you've never experienced it before - the standard says it can happen so you should cater for it. I haven't been hit by a car in the last few decades either but that doesn't mean I wander across roads without looking first.
但不管你以前是否有过这种经历,这都是不重要的——标准说它会发生,所以你应该去迎合它。在过去的几十年里,我也没有被车撞过,但这并不意味着我在没有先看的情况下就在公路上游荡。
And re your edit:
和你重新编辑:
I'm not talking about memory exhaustion, ...
我不是说记忆力衰竭,……
the very definition of memory exhaustion is malloc
not giving you the desired space. It's irrelevant whether that's caused by allocating all available memory, or heap fragmentation meaning you cannot get a contiguous block even though the aggregate of all free blocks in the memory arena is higher, or artificially limiting your address space usage such using the standards-compliant function:
内存耗尽的定义是malloc,它没有提供所需的空间。无论这是由分配所有可用内存引起的,还是堆碎片导致的,这都无关紧要,这意味着即使内存领域中所有空闲块的集合都更高,您也无法获得一个连续的块,或者使用符合标准的函数人为地限制您的地址空间使用:
void *malloc (size_t sz) { return NULL; }
The C standard doesn't distinguish between modes of failure, only that it succeeds or fails.
C标准没有区分失败的模式,只有成功或失败。
#3
8
Any program at all written in c that needs to dynamically allocate more memory than the OS currently allows.
任何用c编写的程序都需要动态地分配比操作系统当前允许的更多的内存。
For fun, if you are using ubuntu type in
为了好玩,如果你正在使用ubuntu类型
ulimit -v 5000
Any program you run will most likely crash (due to a malloc failure) as you've limited the amount of available memory to any one process to a pithy amount.
您运行的任何程序都很可能会崩溃(由于malloc失败),因为您将任何进程的可用内存限制在一个简单的范围内。
#4
4
Just check the manual page of malloc
.
检查malloc的手册页。
On success, a pointer to the memory block allocated by the function.
The type of this pointer is always void*, which can be cast to the desired type of data pointer in order to be dereferenceable.
If the function failed to allocate the requested block of memory, a null pointer is returned.在成功时,指向函数分配的内存块的指针。此指针的类型始终为void*,可以将其转换为所需的数据指针类型,以便可以解除引用。如果函数分配请求的内存块失败,则返回一个空指针。
#5
4
Unless your memory is already completely reserved (or heavily fragmented), the only way to have malloc()
return a NULL
-pointer is to request space of size zero:
除非您的内存已经被完全保留(或严重碎片化),否则让malloc()返回空指针的唯一方法是请求大小为0的空间:
char *foo = malloc(0);
Citing from the C99 standard, §7.20.3, subsection 1:
引用的C99标准,§7.20.3,分段1:
If the size of the space requested is zero, the behavior is implementationdefined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object.
如果请求的空间的大小为零,则行为被实现定义:要么返回一个空指针,要么行为看起来是某个非零值,除非返回的指针不能用于访问对象。
In other words, malloc(0)
may return a NULL
-pointer or a valid pointer to zero allocated bytes.
换句话说,malloc(0)可以将空指针或有效指针返回到零分配字节。
#6
3
Since you asked for an example, here's a program that will (eventually) see malloc
return NULL
:
既然您已经要求了一个示例,下面的程序将(最终)看到malloc返回NULL:
perror();void*malloc();main(){for(;;)if(!malloc(999)){perror(0);return 0;}}
What? You don't like deliberately obfuscated code? ;) (If it runs for a few minutes and doesn't crash on your machine, kill it, change 999
to a bigger number and try again.)
什么?您不喜欢故意混淆代码吗?(如果它运行了几分钟,并且不会在你的机器上崩溃,就把它杀死,把999换成更大的数字,然后再试一次。)
EDIT: If it doesn't work no matter how big the number is, then what's happening is that your system is saying "Here's some memory!" but so long as you don't try to use it, it doesn't get allocated. In which case:
编辑:如果不管这个数字有多大,它都不能工作,那么你的系统会说“这里有一些内存”,但是只要你不尝试使用它,它就不会被分配。在这种情况下:
perror();char*p;void*malloc();main(){for(;;){p=malloc(999);if(p)*p=0;else{perror(0);return 0;}}
Should do the trick. If we can use GCC extentions, I think we can get it even smaller by changing char*p;void*malloc();
to void*p,*malloc();
but if you really wanted to golf you'd be on the Code Golf SE.
应该足够了。如果我们可以使用GCC扩展,我认为我们可以通过更改char*p;void*malloc()来使它更小;void * p * malloc();但如果你真的想打高尔夫球,你就得打高尔夫球。
#7
3
Pick any platform, though embedded is probably easier. malloc
(or new
) a ton of RAM (or leak RAM over time or even fragment it by using naive algorithms). Boom. malloc
does return NULL
for me on occasion when "bad" things are happening.
选择任何平台,尽管嵌入式可能更容易。malloc(或新的)大量的RAM(或随时间而泄漏的RAM,或甚至使用原始算法将其分段)。繁荣。malloc在“坏”事情发生时为我返回NULL。
In response to your edit. Yes again. Memory fragmentation over time can make it so that even a single allocation of an int
can fail. Also keep in mind that malloc
doesn't just allocate 4 bytes for an int
, but can grab as much space as it wants. It has its own book-keeping stuff and quite often will grab 32-64 bytes minimum.
以回应您的编辑。是的。随着时间的推移,内存碎片会导致即使是一个int分配也会失败。还要记住,malloc不只是为int分配4个字节,而是可以获取所需的空间。它有自己的簿记功能,并且通常会获取最少32-64字节的数据。
#8
3
On a more-or-less standard system, using a standard one-parameter malloc, there are three possible failure modes (that I can think of):
在一个或多或少的标准系统中,使用一个标准的单参数malloc,有三种可能的故障模式(我可以想到):
1) The size of allocation requested is not allowed. Eg, some systems may not allow an allocation > 16M, even if more storage is available.
1)不允许分配的大小。一些系统可能不允许分配> 16M,即使有更多的存储空间。
2) A contiguous free area of the size requested, with default boundary, cannot be located in the heap. There may still be plenty of heap, but just not enough in one piece.
2)请求大小的连续*区域(具有默认边界)不能位于堆中。可能仍然有大量的堆,但不是全部。
3) The total allocated heap has exceeded some "artificial" limit. Eg, the user may be prohibited from allocation more than 100M, even if there's 200M free and available to the "system" in a single combined heap.
3)已分配的堆已超过了一些“人工”限制。例如,用户可能被禁止分配超过100米的空间,即使在一个组合堆中有200米的空间可供“系统”使用。
(Of course, you can get combinations of 2 and 3, since some systems allocate non-contiguous blocks of address space to the heap as it grows, placing the "heap size limit" on the total of the blocks.)
(当然,您可以得到2和3的组合,因为一些系统在堆中分配非连续的地址空间块,将“堆大小限制”放置在块的总数上。)
Note that some environments support additional malloc parameters such as alignment and pool ID which can add their own twists.
注意,有些环境支持额外的malloc参数,如对齐和池ID,它们可以添加自己的扭曲。
#9
1
Yes. Malloc will return NULL when the kernel/system lib are certain that no memory can be allocated.
是的。当内核/系统库确定不能分配内存时,Malloc将返回NULL。
The reason you typically don't see this on modern machines is that Malloc doesn't really allocate memory, but rather it requests some “virtual address space” be reserved for your program so you might write in it. Kernels such as modern Linux actually over commit, that is they let you allocate more memory than your system can actually provide (swap + RAM) as long as it all fits in the address space of the system (typically 48bits on 64bit platforms, IIRC). Thus on these systems you will probably trigger an OOM killer before you will trigger a return of a NULL pointer. A good example is a 512MB RAM in a 32bit machine: it's trivial to write a C program that will be eaten by the OOM killer because of it trying to malloc all available RAM + swap.
在现代机器上通常看不到这种情况的原因是,Malloc并不真正分配内存,而是请求为您的程序预留一些“虚拟地址空间”,以便您可以在其中编写。实际上,像现代Linux这样的内核在提交时,它们允许您分配更多的内存,而不是您的系统能够真正提供(交换+ RAM),只要它符合系统的地址空间(通常是在64位平台上的48位,IIRC)。因此,在这些系统中,您可能会在触发一个空指针返回之前触发一个OOM杀手。一个很好的例子是32位机器中的512MB RAM:编写一个将被OOM杀手吃掉的C程序很简单,因为它试图malloc所有可用的RAM + swap。
(Overcomitting can be disabled at compile time on Linux, so it depends on the build options whether or not a given Linux kernel will overcommit. However, stock desktop distro kernels do it.)
(在Linux上可以在编译时禁用过度编译,因此,是否给定的Linux内核会过度提交取决于构建选项。但是,库存桌面发行版内核可以做到这一点。
#1
14
Yes.
是的。
Just try to malloc
more memory than your system can provide (either by exhausting your address space, or virtual memory - whichever is smaller).
只要尝试malloc比您的系统提供更多的内存(通过耗尽您的地址空间,或者虚拟内存——无论哪个更小)。
malloc(SIZE_MAX)
will probably do it. If not, repeat a few times until you run out.
可能会这样做。如果没有,重复几次,直到用完。
#2
20
You need to do some work in embedded systems, you'll frequently get NULL returned there :-)
您需要在嵌入式系统中做一些工作,您将经常得到空返回:-)
It's much harder to run out of memory in modern massive-address-space-and-backing-store systems but still quite possible in applcations where you process large amounts of data, such as GIS or in-memory databases, or in places where your buggy code results in a memory leak.
在现代的大型地址空间和备份存储系统中,内存耗尽要难得多,但在处理大量数据(如GIS或内存中的数据库)的应用程序中,或者在错误代码导致内存泄漏的地方,内存耗尽仍然是可能的。
But it really doesn't matter whether you've never experienced it before - the standard says it can happen so you should cater for it. I haven't been hit by a car in the last few decades either but that doesn't mean I wander across roads without looking first.
但不管你以前是否有过这种经历,这都是不重要的——标准说它会发生,所以你应该去迎合它。在过去的几十年里,我也没有被车撞过,但这并不意味着我在没有先看的情况下就在公路上游荡。
And re your edit:
和你重新编辑:
I'm not talking about memory exhaustion, ...
我不是说记忆力衰竭,……
the very definition of memory exhaustion is malloc
not giving you the desired space. It's irrelevant whether that's caused by allocating all available memory, or heap fragmentation meaning you cannot get a contiguous block even though the aggregate of all free blocks in the memory arena is higher, or artificially limiting your address space usage such using the standards-compliant function:
内存耗尽的定义是malloc,它没有提供所需的空间。无论这是由分配所有可用内存引起的,还是堆碎片导致的,这都无关紧要,这意味着即使内存领域中所有空闲块的集合都更高,您也无法获得一个连续的块,或者使用符合标准的函数人为地限制您的地址空间使用:
void *malloc (size_t sz) { return NULL; }
The C standard doesn't distinguish between modes of failure, only that it succeeds or fails.
C标准没有区分失败的模式,只有成功或失败。
#3
8
Any program at all written in c that needs to dynamically allocate more memory than the OS currently allows.
任何用c编写的程序都需要动态地分配比操作系统当前允许的更多的内存。
For fun, if you are using ubuntu type in
为了好玩,如果你正在使用ubuntu类型
ulimit -v 5000
Any program you run will most likely crash (due to a malloc failure) as you've limited the amount of available memory to any one process to a pithy amount.
您运行的任何程序都很可能会崩溃(由于malloc失败),因为您将任何进程的可用内存限制在一个简单的范围内。
#4
4
Just check the manual page of malloc
.
检查malloc的手册页。
On success, a pointer to the memory block allocated by the function.
The type of this pointer is always void*, which can be cast to the desired type of data pointer in order to be dereferenceable.
If the function failed to allocate the requested block of memory, a null pointer is returned.在成功时,指向函数分配的内存块的指针。此指针的类型始终为void*,可以将其转换为所需的数据指针类型,以便可以解除引用。如果函数分配请求的内存块失败,则返回一个空指针。
#5
4
Unless your memory is already completely reserved (or heavily fragmented), the only way to have malloc()
return a NULL
-pointer is to request space of size zero:
除非您的内存已经被完全保留(或严重碎片化),否则让malloc()返回空指针的唯一方法是请求大小为0的空间:
char *foo = malloc(0);
Citing from the C99 standard, §7.20.3, subsection 1:
引用的C99标准,§7.20.3,分段1:
If the size of the space requested is zero, the behavior is implementationdefined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object.
如果请求的空间的大小为零,则行为被实现定义:要么返回一个空指针,要么行为看起来是某个非零值,除非返回的指针不能用于访问对象。
In other words, malloc(0)
may return a NULL
-pointer or a valid pointer to zero allocated bytes.
换句话说,malloc(0)可以将空指针或有效指针返回到零分配字节。
#6
3
Since you asked for an example, here's a program that will (eventually) see malloc
return NULL
:
既然您已经要求了一个示例,下面的程序将(最终)看到malloc返回NULL:
perror();void*malloc();main(){for(;;)if(!malloc(999)){perror(0);return 0;}}
What? You don't like deliberately obfuscated code? ;) (If it runs for a few minutes and doesn't crash on your machine, kill it, change 999
to a bigger number and try again.)
什么?您不喜欢故意混淆代码吗?(如果它运行了几分钟,并且不会在你的机器上崩溃,就把它杀死,把999换成更大的数字,然后再试一次。)
EDIT: If it doesn't work no matter how big the number is, then what's happening is that your system is saying "Here's some memory!" but so long as you don't try to use it, it doesn't get allocated. In which case:
编辑:如果不管这个数字有多大,它都不能工作,那么你的系统会说“这里有一些内存”,但是只要你不尝试使用它,它就不会被分配。在这种情况下:
perror();char*p;void*malloc();main(){for(;;){p=malloc(999);if(p)*p=0;else{perror(0);return 0;}}
Should do the trick. If we can use GCC extentions, I think we can get it even smaller by changing char*p;void*malloc();
to void*p,*malloc();
but if you really wanted to golf you'd be on the Code Golf SE.
应该足够了。如果我们可以使用GCC扩展,我认为我们可以通过更改char*p;void*malloc()来使它更小;void * p * malloc();但如果你真的想打高尔夫球,你就得打高尔夫球。
#7
3
Pick any platform, though embedded is probably easier. malloc
(or new
) a ton of RAM (or leak RAM over time or even fragment it by using naive algorithms). Boom. malloc
does return NULL
for me on occasion when "bad" things are happening.
选择任何平台,尽管嵌入式可能更容易。malloc(或新的)大量的RAM(或随时间而泄漏的RAM,或甚至使用原始算法将其分段)。繁荣。malloc在“坏”事情发生时为我返回NULL。
In response to your edit. Yes again. Memory fragmentation over time can make it so that even a single allocation of an int
can fail. Also keep in mind that malloc
doesn't just allocate 4 bytes for an int
, but can grab as much space as it wants. It has its own book-keeping stuff and quite often will grab 32-64 bytes minimum.
以回应您的编辑。是的。随着时间的推移,内存碎片会导致即使是一个int分配也会失败。还要记住,malloc不只是为int分配4个字节,而是可以获取所需的空间。它有自己的簿记功能,并且通常会获取最少32-64字节的数据。
#8
3
On a more-or-less standard system, using a standard one-parameter malloc, there are three possible failure modes (that I can think of):
在一个或多或少的标准系统中,使用一个标准的单参数malloc,有三种可能的故障模式(我可以想到):
1) The size of allocation requested is not allowed. Eg, some systems may not allow an allocation > 16M, even if more storage is available.
1)不允许分配的大小。一些系统可能不允许分配> 16M,即使有更多的存储空间。
2) A contiguous free area of the size requested, with default boundary, cannot be located in the heap. There may still be plenty of heap, but just not enough in one piece.
2)请求大小的连续*区域(具有默认边界)不能位于堆中。可能仍然有大量的堆,但不是全部。
3) The total allocated heap has exceeded some "artificial" limit. Eg, the user may be prohibited from allocation more than 100M, even if there's 200M free and available to the "system" in a single combined heap.
3)已分配的堆已超过了一些“人工”限制。例如,用户可能被禁止分配超过100米的空间,即使在一个组合堆中有200米的空间可供“系统”使用。
(Of course, you can get combinations of 2 and 3, since some systems allocate non-contiguous blocks of address space to the heap as it grows, placing the "heap size limit" on the total of the blocks.)
(当然,您可以得到2和3的组合,因为一些系统在堆中分配非连续的地址空间块,将“堆大小限制”放置在块的总数上。)
Note that some environments support additional malloc parameters such as alignment and pool ID which can add their own twists.
注意,有些环境支持额外的malloc参数,如对齐和池ID,它们可以添加自己的扭曲。
#9
1
Yes. Malloc will return NULL when the kernel/system lib are certain that no memory can be allocated.
是的。当内核/系统库确定不能分配内存时,Malloc将返回NULL。
The reason you typically don't see this on modern machines is that Malloc doesn't really allocate memory, but rather it requests some “virtual address space” be reserved for your program so you might write in it. Kernels such as modern Linux actually over commit, that is they let you allocate more memory than your system can actually provide (swap + RAM) as long as it all fits in the address space of the system (typically 48bits on 64bit platforms, IIRC). Thus on these systems you will probably trigger an OOM killer before you will trigger a return of a NULL pointer. A good example is a 512MB RAM in a 32bit machine: it's trivial to write a C program that will be eaten by the OOM killer because of it trying to malloc all available RAM + swap.
在现代机器上通常看不到这种情况的原因是,Malloc并不真正分配内存,而是请求为您的程序预留一些“虚拟地址空间”,以便您可以在其中编写。实际上,像现代Linux这样的内核在提交时,它们允许您分配更多的内存,而不是您的系统能够真正提供(交换+ RAM),只要它符合系统的地址空间(通常是在64位平台上的48位,IIRC)。因此,在这些系统中,您可能会在触发一个空指针返回之前触发一个OOM杀手。一个很好的例子是32位机器中的512MB RAM:编写一个将被OOM杀手吃掉的C程序很简单,因为它试图malloc所有可用的RAM + swap。
(Overcomitting can be disabled at compile time on Linux, so it depends on the build options whether or not a given Linux kernel will overcommit. However, stock desktop distro kernels do it.)
(在Linux上可以在编译时禁用过度编译,因此,是否给定的Linux内核会过度提交取决于构建选项。但是,库存桌面发行版内核可以做到这一点。