内存池的初始块大小

Initial block size for memory pool

本文关键字:内存      更新时间:2023-10-16

我正在使用C++模板实现一个内存池类,我想知道块的大小应该是多少。例如:

template <typename T>
class Mempool {
  unsigned char* block;
  // constructor. 
  Mempool() {
    block = malloc(sizeof(T)*DEFAULT_N)
  }
};

在上面的例子中,块大小实际上取决于类型T和要创建的元素数量的默认值。这样做的最佳(或常见)做法是什么?我应该在这里考虑块大小的内存对齐吗?

我只能给出一些一般性的建议,因为这在很大程度上取决于实际用例:

对齐:我想这个池应该确保其中的对象正确对齐。这意味着您可能希望将对象放置在至少是std::alignment_of<T>::valuealignof(T)的倍数的内存位置。

缓存友好性:池还可以将对象位置四舍五入到缓存行大小的倍数,因此(小)对象永远不会跨两个缓存行放置,而是始终位于一个缓存行中。

填充:如果对象很小(只有几个字节),但你有很多对象,那么任何额外的填充都可能会大大增加内存需求,这取决于应用程序是否会出现问题。当对象没有放在紧密的位置并且有很多缓存未命中时,过多的填充实际上可能会影响性能。

底层内存管理:最后,良好的块大小也可能取决于底层存储。您可能希望您的分配大小与操作系统页面大小相匹配,或者使用它们的倍数。此外,如果malloc代价高昂,那么您可能希望尽可能少地调用它,以避免系统调用开销和争用。在malloc更便宜的环境中,可以更频繁地使用较小的初始块大小和malloc,尽管malloc仍将有一些开销。其中很大一部分是特定于操作系统的。

因此,无论您选择什么初始大小,都应该衡量一些典型工作负载的内存使用率和分配性能。这将使你能够做出比纯粹猜测更具教育意义的估计。

最后,还有现成的malloc替换,如tcmallocjemalloc,它们可能具有与操作系统的malloc完全不同的特性。因此,一个好的选择是检查其中一个,而不是滚动自己的分配器。