C++, Free-Store vs Heap

154

使用 new/delete 进行动态分配被称为在自由存储区上进行,而 malloc/free 操作则使用

实际上是否存在区别?编译器是否区分这两个术语(自由存储区,而不是new/malloc)?我想知道。


1
在嵌入式系统上,可能会有区别。在大多数(所有?)个人电脑上,new/delete自由存储区是堆。 (在我的机器上,new/delete,new[]/delete[]和malloc/free有单独的堆。但它们都是堆。) - Eljay
7个回答

96

对于C++来说,自由存储区(free store)和堆(heap)之间的区别已经变得纯粹是概念上的区别,就像收集虫子和饼干的罐子一样,它们被标记为不同的东西。这种标记旨在强调永远不要混合使用"new"和"delete"以及"malloc"、"realloc"或"free"(或位级设置)。

在面试中,可以说"new"和"delete"使用自由存储区,而"malloc"和"free"使用堆;"new"和"delete"分别调用构造函数和析构函数,而"malloc"和"free"则不会。然而,你经常会听到内存段实际上在同一个区域中,但这可能是与编译器有关的,也就是说,它们都可以将不同的内存空间指定为池(虽然不确定为什么会这样)。


92

参见http://www.gotw.ca/gotw/009.htm, 它比我能做得更好地描述了堆(heap)和自由存储区(free-store)之间的差异:

自由存储区:

自由存储区是通过new/delete分配/释放的两个动态内存区域之一。对象的生命周期可以少于分配存储器的时间,即自由存储区对象可以在未立即初始化的情况下分配内存,也可以在未立即释放内存的情况下被销毁。在存储器分配但对象生命期之外的时期,可以通过void *访问并操作该存储器,但无法访问proto-object的非静态成员或成员函数,也不能获取它们的地址或进行其他操作。

堆:

堆是另一个动态内存区域,通过malloc/free及其变体进行分配/释放。请注意,虽然特定编译器中默认全局的new和delete可能是基于malloc和free实现的,但堆不同于自由存储区,从一个区域分配的内存不能安全地在另一个区域释放。从堆中分配的内存可以通过placement new构造函数和显式析构用于类类型对象。如果这样使用,则关于自由存储区对象生命期的注释同样适用于此处。


28
我不同意。在动态分配的背景下,“heap”一词既不被C++标准使用,也不被C99使用(我没有C++所参考的C89版本,如果它使用这个单词,请随意纠正我)。我找不到相关的GotW文章发布日期,但由于它提到了草案,显然是标准之前的文章。 - avakar
6
在我看来,这只是术语问题。例如,Stroustrup先生不区分“堆”和“自由存储”:http://www.stroustrup.com/Programming/17_free_store.ppt,第12页。在C++之前很久,“堆”一词就被用作动态内存的同义词,自Lisp时代(1960年代)就开始使用堆数据结构进行内存分配。 - Spock77
3
我通常认为堆(通过maloc/free)是一种“原材料”供应商。你请求一块内存,你得到它没有花哨的东西。你必须自己构建任何结构。自由存储器(new/delete)更像是一个“成品”供应商。你请求一个对象,它被分配一些空间,并且该对象被建立和准备好供你使用。当它完成后,它会被很好地清理干净。 - Anshuman Kumar

37

Mike Koval的回答很好地涵盖了理论方面。但实际上,在大多数情况下,它们几乎总是指内存的同一区域 - 大多数情况下,如果你深入挖掘编译器实现new,你会发现它调用了malloc()

换句话说:从机器的角度来看,堆和自由存储区域是相同的东西。这个区别存在于编译器中。

更让人困惑的是,在C++出现之前,我们所说的“堆”是现在被称为“自由存储区域”的意思。


调用 new + delete 相当于调用 new + 析构函数 + free 吗? - joepol
1
这是未定义行为,因为标准没有说明newmalloc()是否从同一堆中获取。实际上,大多数new的实现只是在底层调用malloc()。但你不能指望这样。 - Crashworks

7
术语“堆”也可能指特定的数据结构,但在C++的malloc、free、new和delete操作中,“堆”和“自由存储区”这两个术语几乎可以互换使用。

4

Free Store是一个程序可以用来在执行过程中动态分配内存的未分配堆内存池。 每个程序都提供了一组未分配的堆内存池,程序可以在执行期间利用它们。 这组可用内存池被称为程序的free store。 分配给free store的内存是无名的。


3
堆和自由存储区不应该互通。 在一些受限制的环境下,例如在带有C++11标准库的AVR 8位微控制器中,它们甚至不能在同一个程序中使用。自由存储区和堆在同一内存空间中进行分配,会相互覆盖结构和数据。 在这种情况下,自由存储区与堆不同且不兼容,因为“new/delete free store library”比“Malloc/free/realloc/calloc heap library”更简单(而且更快),因此可以为C++嵌入式程序员提供巨大的内存使用优势(在只有512字节RAM的情况下)。
请参阅8位C++11/14标准库:https://github.com/ambroise-leclerc/ETL/tree/master/libstd

3

我不记得标准文件中曾经提到过“堆”这个词,除了在描述像push_heap等堆函数时。所有动态分配都是在自由存储区(free-store)上执行的。


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