当用尽malloc
之类的可用内存时,它会失败吗?还是有其他原因?
答案 0 :(得分:11)
任何分配函数(malloc
,realloc
,calloc
以及POSIX,posix_memalign
)可能由于以下任何原因而失败,可能还有其他原因:
malloc
在这种情况下不会失败,但是当OS发现不存在时,操作系统会杀死一个或多个程序真的有足够的物理内存来绕过。但是在健壮的系统(包括禁用过度使用的Linux)上,如果没有物理内存,malloc
将失败。请注意,严格来说,出于任何原因,分配函数可以随时失败。最小化失败是一个实施质量问题。即使减少对象的大小,realloc
也可能会失败;这可能发生在严格按大小分配分配的实现上。当然,在这种情况下,您可以继续使用旧的(较大的)对象。
答案 1 :(得分:4)
你应该认为realloc
是这样的:
void *realloc(void *oldptr, size_t newsize)
{
size_t oldsize = __extract_size_of_malloc_block(oldptr);
void *newptr = malloc(newsize);
if (!newptr)
return 0;
if (oldsize > newsize)
oldsize = newsize;
memcpy(newptr, oldptr, oldsize);
free(oldptr);
return newptr;
}
实现可以能够比这更有效地执行特定情况,但完全如图所示的实现是100%正确的。这意味着realloc(ptr, newsize)
可能会在malloc(newsize)
失败的任何时候失败;特别是即使你缩减了分配,也会失败。
现在,在现代桌面系统上,有一个很好的例子,即不尝试从malloc
失败中恢复,而是将malloc
包装在一个函数(通常称为xmalloc
)中,以终止如果malloc
失败,立即编程;自然地,相同的论点适用于realloc
。案例是:
malloc
失败之前,用户将厌倦了他们的颠簸磁盘并强制终止您的程序。malloc
调用失败的填充程序库(这样的填充程序最多是困难的,最坏的情况是不可能的,创建,取决于操作系统),你必须测试2 N 失败模式,其中N是程序中对malloc的调用次数。参数1和2不适用于嵌入式或移动系统(但是!),但参数3在那里仍然有效。
参数3仅适用于必须在每个呼叫站点检查和传播分配失败的程序。如果你很幸运能够使用C ++,因为它可以被使用(例如有例外),你可以依靠编译器为你创建错误恢复路径,因此测试负担大大减少了。现在,在任何更高级别的语言中都可以使用异常和垃圾收集器,这意味着即使您愿意也不用担心分配失败。
答案 2 :(得分:1)
我会说它主要是针对具体实施的。某些实现可能很可能失败。有些人可能会在realloc之前使程序的其他部分失败。始终保持防守并检查它是否失败。
请记住释放您尝试重新分配的旧指针。
ptr=realloc(ptr,10);
总是可能发生内存泄漏。
总是这样做:
void *tmp=ptr;
if(ptr=realloc(ptr,10)==NULL){
free(tmp);
//handle error...
}
答案 3 :(得分:0)
你有两个问题。
在大多数现代系统中malloc
或realloc
失败的可能性微不足道。只有在虚拟内存不足时才会出现这种情况。您的系统将无法访问内存而不是保留它。
W.r.t失败realloc
和malloc
几乎相等。 realloc
可能另外失败的唯一原因是你给它一个不好的参数,即没有用malloc
或realloc
分配的内存或以前曾free
的内存。 } d。
编辑:鉴于R.的评论。是的,您可以配置系统,使其在分配时失败。但首先,AFAIK,这不是默认值。它需要以这种方式配置的权限,作为应用程序程序员,这不是你可以依赖的。其次,即使您有一个以这种方式配置的系统,这只会在您的可用交换空间被占用时出错。通常,您的机器在此之前很久就会无法使用:它将在您的硬盘上进行机械计算(AKA交换)。
答案 4 :(得分:0)
现在,在现代台式机系统上,有很强的理由不尝试从
malloc
故障中恢复,而是将malloc
包装在一个函数中(通常称为xmalloc
),该函数终止了如果malloc
失败,请立即编程;
自然,同一论点也适用于realloc
。
您可以看到Git 2.29(2020年第4季度)适用的原理:xrealloc()
可能发送已释放的非NULL指针,该指针已得到修复。
请参见commit 6479ea4的Jeff King (peff
)(2020年9月2日)。
(由Junio C Hamano -- gitster
--在commit 56b891e中合并,2020年9月3日)
xrealloc
:不要重用零长度realloc()
释放的指针签名人:杰夫·金
此修补程序修复了
xrealloc(ptr, 0)
在某些平台(至少包括glibc
)上可以双重释放并破坏堆的错误。C99标准提到
malloc
(第7.20.3节):If the size of the space requested is zero, the behavior is implementation-defined: 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.
所以我们可能会返回
NULL
,或者可能会得到一个实际的指针(但是我们不允许查看其内容)。为简化代码,我们的
xmalloc()
通过将NULL
转换为单字节分配来处理它。 这样,呼叫者将获得一致的行为。这是在4e7a2eccc2中完成的(“?alloc
:要求输入零字节时不返回NULL
”,2005-12-29,Git v1.1.0-{{3} }。我们还对
xcalloc()
和xrealloc()
进行了相同的处理。根据C99,这很好;上面的文字在一个段落中适用于所有三个段落。但是在这种情况下,我们传递给
realloc()
的内存会怎样?即,如果我们这样做:ret = realloc(ptr, 0);
和“
ptr
”为非NULL,但我们得到NULL
的返回:“ptr
”仍然有效吗?
C99并未专门针对这种情况,但表示(见第7.20.3.4节):The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size.
因此,“
ptr
”现在已解除分配,我们只能查看“ret
”。
而且由于“ret
是NULL
,这意味着我们根本没有分配的对象。但这还不是全部。它还说:If memory for the new object cannot be allocated, the old object is not deallocated and its value is unchanged. [...] The realloc function returns a pointer to the new object (which may have the same value as a pointer to the old object), or a null pointer if the new object could not be allocated.
因此,如果我们看到
NULL
返回的大小非零,则可以预期原始对象仍然仍然有效。
但是,如果大小不为零,则模棱两可。NULL
返回可能意味着失败(在这种情况下对象是有效的),或者可能意味着我们没有成功分配任何东西,并使用NULL
来表示。
glibc
的{{1}}联机帮助页明确指出:realloc()
同样,此StackOverflow回答“ merge”:
声称C89提供了类似的指导(但我没有副本可以验证它。)评论What does
malloc(0)
return?声称Microsoft的CRT行为相同。但是我们当前的“重试1个字节”代码再次传递了原始指针。
因此,在[...]if size is equal to zero, and ptr is not NULL, then the call is equivalent to free(ptr).
上,我们有效地glibc
指针,然后再次尝试free()
,这是未定义的行为。这里最简单的解决方法是将“
realloc()
”(我们知道是ret
)传递给后续的NULL
。
但这意味着不释放原始指针的系统将泄漏它。尚不清楚是否存在这样的系统,并且对标准的解释似乎不太可能(在这种情况下,我希望系统不会释放以简单地返回原始指针)。
但是从安全的角度来看,这很容易犯错,并且根本不会向realloc()
传递零大小。