我总是假设heap (data structure)用于实现heap (dynamic memory allocation),但我被告知我错了。
通常情况下,如何实现堆(例如,典型的malloc
例程或Windows的HeapCreate
等实现的堆)?他们使用什么数据结构?
在线搜索时,我看到了 吨 有关如何实施严重限制的 的说明的说明。 仅举几例,我已经看到了很多关于如何实现的描述:
这很有趣,他们都避免了更难的问题:
如何实现“普通”通用堆(如malloc
,HeapCreate
背后的那个)?
他们使用什么数据结构(可能还有算法)?
答案 0 :(得分:14)
分配器往往非常复杂,并且在实施方式上往往存在很大差异。
你无法用一种常见的数据结构或算法来描述它们,但有一些共同的主题:
如果您想查看一些源代码,jemalloc是一个现代化的高性能分配器,应该具有其他常见分配器的复杂性。 TCMalloc是另一个常见的通用分配器,他们的网站涉及所有gory实现细节。英特尔的Thread Building Blocks有一个专门为高并发而构建的分配器。
Windows和* nix之间可以看到一个有趣的区别。在* nix中,分配器对应用程序使用的地址空间具有非常低级别的控制。在Windows中,你基本上有一个粗粒度的慢速分配器VirtualAlloc
来基于你自己的分配器。
这导致* nix兼容的分配器通常直接为您提供malloc
/ free
实现,假设您只使用一个分配器(否则它们会相互踩踏)虽然特定于Windows的分配器提供了额外的功能,但只保留malloc
/ free
,并且可以和谐使用(例如,您可以使用HeapCreate创建可以与其他人一起工作的私有堆)。 / p>
在实践中,这种灵活性交易使得* nix分配器在性能方面略有提升。很少见到应用程序故意在Windows上使用多个堆 - 主要是因为不同的DLL使用不同的运行时,每个都有自己的malloc
/ free
,这可能会引起很多麻烦如果你没有勤奋地跟踪一些记忆来自哪个堆。
答案 1 :(得分:6)
注意:以下答案假设您使用的是具有虚拟内存的典型现代系统。 C和C ++标准不需要虚拟内存;因此,当然,如果没有此功能,您不能依赖硬件上的这些假设(例如,GPU通常没有此功能;也不会像PIC那样使用极小的硬件。)
这取决于您使用的平台。堆可以是非常复杂的野兽;他们不只使用单一的数据结构;并且没有“标准”数据结构。即使堆代码所在的位置也不同,具体取决于平台。例如,堆代码通常由Unix上的C Runtime框提供;但通常由Windows上的操作系统提供。
brk
or sbrk
)。许多堆只是尝试重用程序本身不再使用的内存,而不是尝试将内存返回给系统,而不是将内存返回给操作系统。这在Windows上不太常见,因为它等同于sbrk
(VirtualAlloc
)没有此限制。 (但是像sbrk
一样,它非常昂贵并且有一些注意事项,例如只分配页面大小和页面对齐的块。所以堆尽量尝试尽可能少地调用。)RtlHeap
为不同的已知块大小维护了许多这样的数据结构。 (例如,对于大小为16的块,它会有一个)RtlHeap称这些为“后备列表”。我发现讨论主要平台上常用分配策略的最佳参考是书Secure Coding in C and C++, by Robert Seacord。第4章的所有内容都专门用于堆数据结构(以及当用户错误地使用所述堆系统时引起的问题)。