2016-11-20 116 views
1

如果这听起来像一个幼儿园问题,那么原谅我);但是,在C++中,堆被用于内存分配,因为......(至少在80年代)。它是这个工作的最佳算法,还是我们刚刚陷入困境(就像javascript所发生的那样)?是否所有(非嵌入式)操作系统都使用堆来存储内存?为什么我们使用堆来存储内存?

编辑: 那么,使用什么结构/算法ARE。它如何(如果)与堆算法有关?

没有必要与“堆栈”分配(它遍布整个网络)进行比较,还是讨论C++语义 - 当今的内存堆是什么?

+2

这些日子里,内存分配“堆”几乎从来没有被构造成任何类型的最大或最小堆。我认为其中一个真正的早期实现使用了堆数据结构,而这个术语刚刚停滞不前。 – user2357112

+1

与memiry alocation相关的堆不是算法,也不是数据结构。这只是“动态存储”的另一个名称。 –

回答

2

这听起来像你在heap"heap"混淆。堆数据结构很少用于动态内存分配。

现在,重新:为什么动态内存分配?有时你不知道你需要多少内存,也不想仅仅分配一个巨大的缓冲区以防万一。在堆上分配允许您在运行时必须更改的存储空间量。

1

在这种情况下,所讨论的“堆”与称为堆的数据结构不同。

通常“堆”是指由malloc/realloc/free管理的存储器。这些通常在合理编写的C++中很少使用(如果有的话)。

对于C++中的动态分配,您更经常使用newdelete(至少间接地,例如通过容器使用的std::allocator<T>)。有些人有时也将此称为“堆”,但试图更加合适的人往往将其称为“自由存储”(这是标准中使用的措词)。

但是,无论如何,很少(如果有的话)涉及实际的堆。既没有规定(或意图指代)用于管理存储器的数据结构。

对于什么是值得的,我看到用于管理内存的实际堆栈最接近的是一个“伙伴系统”分配器(但我在实际使用中看到了相对较少的这些,即使Knuth进入到

至于使用何种结构对他们相当多的细节,一个非常普遍的结构,就像一个块的链表,每块至少会记录自己的大小。

常见的基本算法是最合适的,最合适的和最适合的。

  • 最合适的意思是找到足够大的最小空闲块以满足请求。要做到这一点,您通常会按照大小按升序排列空闲块列表,因此足够大的第一个块也是最合适的。
  • 最糟糕的情况意味着始终从最大的块开始。要做到这一点,您通常会按大小降序排列空闲块列表。这样,无论是列表中的第一个块是最大的,因此您总是使用它,或者分配失败(或者您需要执行一些操作,比如从操作系统中分配更多)。在大多数情况下,你仍然需要做一些列表遍历,因为你将最大的块分成两部分:你分配给用户的部分,剩下的部分,然后按顺序重新插入到列表中以其新的规模。
  • 第一个拳头意味着您遍历列表并使用可以满足分配的第一个块。

在所有情况下,您通常都会有块分割的策略。也就是说,如果一个分配要求的大小小于所选择的块的大小,你可以选择如何将块保留原样,并给用户一点额外的内存,否则将该块分成两块:一块用于以满足分配,另一个回到免费清单。在大多数情况下,您尽量避免创建小块,因此除非“遗留”部分大于特定大小,否则您只需保留原始块。

如果他们没有多想事情,大多数人的第一本能就是使用最合适的。最合适的问题是,当你分割一个块时,它会产生最小的剩余块,因此趋于最终会产生许多无法满足任何分配的小块。如果你确实使用它,你通常会设置一个相当高的阈值,在那里你将保持一个块完整无损,而不是分割它。

最糟糕的尝试抵消这一点。尽管可能会分割最大的块,但它往往留下最大的剩余块,因此它最有可能被使用。

也有混合,如精确适合,最差。也就是说,不是总是使用最大的块,而是首先寻找一个恰好符合(或足够接近以至于不会分割该块)的块,并且只有在失败时才会分割最大的块。

如果您按照某种顺序保留空闲块,还会使用某种或某些树的明显修改来存储块,因此您可以在大致对数时间而不是线性时间内找到块。

+0

这确实令人困惑......我写了几个std:分配器在我的生活中,所以是的,我知道它的一切... – rubmz

2

在内存分配的上下文中,堆不是数据结构或算法。它更符合英语定义,它在某些地方本质上是一个非结构化的东西。

历史上,早期的计算机系统只有很少的内存,而早期的操作系统只能管理少量的内存。像64K(即千字节,不是兆字节或千兆字节)的数量在早期实际上是大量的内存,而早期的操作系统的设计能够支持不超过640K的程序运行。这是全部内存。

当某台计算机拥有两个或更多独立的物理内存芯片库时,这实际上是一项创新。其中之一用于在内存中运行程序,其他程序用于存储程序所需的数据,其方式可以比从磁盘读取数据更快地进行访问。这两个内存区域分别被称为栈和堆。需要使用特殊设备驱动程序访问堆。可用的堆内存量通常(并非总是)比堆栈内存大得多。在实践中,在C和C++的早期实现中,静态和自动变量通常使用堆栈内存,动态分配内存(malloc()等)使用堆。即使这个区别现在在很大程度上是学术性的(例如,堆和堆栈限制被设置为逻辑配额,而不是反映物理上可用的存储区),名称仍然存在。

因此,在现代C和C++中,“堆”的正确术语是“动态分配的内存”。动态内存分配(例如像malloc()这样的函数)不一定使用被称为“堆”的任何内存区域(尽管,显然,主机系统必须使用一些数据结构来跟踪内存分配和释放)。

+0

我认为你的答案错过的是什么结构堆使用。历史和堆栈比较众所周知...... – rubmz

+0

这不仅仅是错过了这一点,而且它所说的相当数量的东西显然是错误的。 –

相关问题