通读《Apache模块书》,我在3.4.3部分遇到了这个说法:
"第二个好处是,在大多数平台上,池分配比malloc更快!"
一个悬而未决的问题,我意识到,但是......好吧,为什么?
除了 Lars 关于位置的观点外,池分配只是与 malloc
不同的速度/灵活性权衡。
malloc
必须跟踪每个分配的块,能够单独释放块,处理自由块碎片和合并,有一些策略来选择从几个自由块中分配哪个,等等。
这对于通用分配器是必需的,但池通过使调用方静态决定其中一些行为来避免所有这些复杂性(以及相关的空间和运行时开销)。
Apache的例子似乎只允许整个池的释放(所以它就像一个竞技场分配器)。这意味着它不需要跟踪单个分配记录、它们的生命周期和零散的免费存储。 它只需要跟踪一个(或多个)大块内存,并更新指向下一个未使用空间的指针。 请注意,即使这些大块是使用 malloc
分配的,此成本通常也会分摊到许多池分配中。
其他池类型可能仅限于相同大小(或类型)的对象,这进一步简化了它们;它们甚至可以以接近零的成本保持LIFO自由列表,允许每条记录的释放。
池分配策略可以带来更好的性能以两种方式。在数据结构遍历的应用程序中匹配数据分配顺序,池化策略可以暴露更规律的步伐。
例如,考虑搜索通过记录的链接列表。每条记录由一个键字段、数据字段和指向列表中的下一条记录。访问键和下一个字段连续,直到找到匹配项。只有这样访问数据字段。如果数据存储在每个记录本身就是一个堆对象,更糟糕的是,数据在大小形式记录到下一个,有各种不良影响关于工作集的空间局部性。即数据不必要地从内存中获取,消耗宝贵的带宽。
此外,由于可变长度数据干预键和下一个字段,记录中的步幅,并且跨连续记录将显示不规则。因此,不同对象类型的分离可以改善空间局部性,以及随之而来的整体性能。
此外由于池分配可能会暴露更规律的步幅,因此简单的预取策略可以预测未来的引用并缩短其内存访问延迟。