当尝试释放由堆管理器分配的比要求更多的内存时会发生什么?

8

这个问题在我的面试中被问到。

假设char *p=malloc(n)分配了比n更多的内存,即分配了N个字节的内存,并使用free(p)释放了分配给p的内存。

堆管理器是否能执行此类错误分配?现在会发生什么情况,会释放n个字节还是N个字节?

有没有办法找到已释放的内存量?

编辑

有没有办法找到已释放的内存量?

虽然不是最好的方法,但是mallinfo()可以提供一些信息,正如“Fred Larson”所指出的那样。


6
你认为这种分配方式有何缺陷?不管 malloc() 分配了多少个“实际”字节,你只能使用 n 个字节,并且 free() 将释放所有已分配的字节。大多数 malloc 实现都会分配比请求的空间更多,以提高效率。一个实现定义了 mallocfree,根据定义,它们必须在分配方案上达成一致。 - Alok Singhal
5个回答

9
是的,几乎每次使用malloc()时都会发生这种情况。 malloc块头包含有关块大小的信息,当调用free()时,它会将该数量返回到堆中。这并不是故障,而是预期操作。
例如,一个简单的实现可能仅在返回指针之前的空间中存储块的大小。然后,free()看起来像这样:
void free(void *ptr)
{
    size_t *size = (size_t *)ptr - 1;

    return_to_heap(ptr, *size);
}

在这里,“return_to_heap()”是指一个函数,它实际上将指定的内存块返回到堆中以供将来使用。

有没有一种方法可以找出释放了多少内存? - Rozuur
@rozuur:malloc()分配的所有内存都将由free()释放。我认为你真正想问的是如何找出分配了多少内存。(答案是什么?如果分配成功,至少与请求的一样多。) - Bill
1
rozuur:看一下这个页面:http://msdn.microsoft.com/en-us/library/ms220938(VS.80).aspx它介绍了当你请求一块内存时实际上发生了什么。大多数实现都非常类似于这个过程。 - ThePosey
1
@rozuur 重要的是,分配的大小真的不重要。这些都是实现细节,除非你怀疑它们会导致问题,否则不必过于担心它们,而大多数情况下它们不会导致问题。 - asveikau
@Rozur,为了后人!1)所有的内存分配都将被释放(根据问题而定)。2)能否准确地找出分配了多少内存取决于内存管理器是否发布此信息。3)没有标准函数可以获得malloc()分配的字节数(尽管不同的供应商可能会选择提供这样的函数)。4)许多内存管理器将“n”向上舍入到下一个二的幂,从而确保您永远不会浪费超过一半的内存。 - André Caron

4
是的,堆管理器可以返回一个大于n字节的块。使用free释放返回的指针是完全安全的(也是必需的!),free将会释放所有内存。
许多堆实现通过在堆中插入元数据块来跟踪它们的分配情况。free将查找该元数据以确定需要释放多少内存。这是与实现相关的,因此无法知道malloc给了你多少内存,通常你不应该关心。

1

通常堆管理器将释放其分配的任何内容。它会在某个地方存储这些信息,并在调用free()时查找。

如果堆管理器分配的内存超过了请求的内存,那么它并不是“有故障”的。堆管理器通常使用固定块大小,并在满足请求时向上舍入到下一个适当的块大小。堆管理器的工作是尽可能高效,而且通常一些小的低效率会带来大的效率提升。


经常情况下,大的效率提升来自于一些小的低效率。 - caseman

1

这是malloc的默认行为。它将返回NULL或指向至少与所请求的内存长度相同的内存部分的指针。因此,是的,free必须能够处理释放比所请求的内存更长的内存。

查找实际上已释放或分配了多少内存是一个特定于平台的问题。


1

其他答案已经很好地解释了块大小是如何处理的。要找出有多少内存被释放,我唯一能想到的解决方案就是在释放之前和之后调用mallinfo()


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