在设计内存池时如何考虑对齐?

时间:2010-08-19 22:11:11

标签: c++ memory

我正在为一个小型游戏引擎开发内存池。

主要用途是作为隔离存储;池包含特定类型和大小的对象。目前,池可用于存储任何内容,但分配将在特定大小的块中完成。大部分内存需求将立即分配,但如果需要协助调整(几乎固定大小),可以启用“过度增长”。

问题是,在考虑内存对齐时,我开始有些偏执。我只习惯8位处理器上的原始内存管理,其中所有内容都是字节对齐的。

我让用户(我)指定所需的块大小,这些块在隔离存储的情况下将是我将要存储在其中的对象的大小。

当前的方法是分配一大块内存blocks * (desired_size + header_size)并将对象放入其中,每个块都有一个标头;对象显然会直接位于此标题后面。

在我的场景中,关于内存对齐,我需要考虑什么?

我到目前为止得出的答案是,只要desired_size代表 n 字节对齐的数据;标题由编译器以及实际数据正确对齐和打包,存储在块中的所有内容都将 n - 字节对齐。

n是平台所需的任何边界。我目前的目标是x86,但我不想在我的代码中对平台做出任何假设。

我使用过的一些资源:

修改

上传的小样本代码可能对将来困扰我的任何人有所帮助here

5 个答案:

答案 0 :(得分:7)

保证malloc的分配与编译器提供的任何类型对齐,因此对齐任何对象[*]。

当您的标头的对齐要求小于实施的最大对齐要求时,存在危险。那么它的大小可能不是最大值的倍数。对齐,所以当你尝试使用buf + header_size作为指向 具有最大值的东西的指针时。对齐,它是错位的。就C而言,这是未定义的行为。在英特尔它的工作,但速度较慢。在某些ARM上,它会导致硬件异常。在某些ARM上,它默默地给出了错误的答案。因此,如果您不想在代码中对平台做出假设,则必须处理它。

基本上我有三个技巧可以确保您的标题不会导致错位:

  • 使用特定于实现的对齐编译指示来强制解决问题。
  • 使用特定于平台的结构布局和对齐知识,以确保其大小恰好是系统上最大对齐要求的倍数。通常这意味着,“如果需要,可以将额外的int作为填充,使其成为8倍,而不仅仅是4倍”。
  • 使标头成为每种标准类型的union,以及您实际想要使用的结构。在C中运行良好,但如果您的标题对于工会会员资格无效,则在C ++中会遇到问题。

或者,您可以将header_size定义为不sizeof(header),但要将该大小四舍五入为2的“2足够大”的倍数。如果你浪费了一点内存,那就这样吧,你可以随时拥有一个“可移植性标题”来定义这种事物,这种方式不是纯粹与平台无关的,而是可以很容易地适应新平台。

[*]有一个常见的例外是SIMD类型过大。由于它们是非标准的,仅仅因为它们而对每个分配进行16对齐是浪费的,所以它们会被手动放在一边,你需要特殊的分配功能。

答案 1 :(得分:2)

您的编译器已经对齐将存储在池中的对象和结构的成员。使用适合您的体系结构的默认打包,对于32位内核,通常为8。您只需确保从池中生成的地址相应对齐。在32位操作系统上应该是8字节的倍数。

当对象跨越CPU缓存行边界时,错误对齐对象可能非常昂贵。跨越两个缓存行的双倍需要读取或写入的时间长达三倍。

答案 2 :(得分:2)

我也调整了内存对齐方式。首先要理解的是每个对象都有自己的内存对齐要求,这个要求(最多)是对象本身的大小。幸运的是,它通常更小。

有两种类型的工具可以帮助编写正确的内存分配器(C ++ 0x,它们可以在大多数STL的std::tr1中找到):

  • std::alignment_of将对齐作为编译时值
  • std::aligned_storage根据参数
  • 给出对齐的存储空间

与他们两个人合作,你就会得到你需要的东西。

然而,您的设计稍微偏离基础,而不是太多介意,因为您的标题通常不会与存储的对象具有相同的对齐要求。

template <class T, size_t N>
struct Block
{
  // Header bits

  typedef std::aligned_storage<
      N*sizeof(T),
      std::alignment_of<T>::value
  >::type buffer_type;
  buffer_type mBuffer;
};

两个注释:

  • Block本身可能有不同的对齐方式,但无关紧要
  • 您可以使用sizeof进行对齐,即使有点浪费也能保证正常工作

最后,你也可以在没有所有这些和一些指针算术的情况下成功,但是因为它被提供....

答案 3 :(得分:1)

使用http://msdn.microsoft.com/en-us/library/bb982233.aspx - std :: alignment_of。这样可以确保对于您分配到池中的每个T,您将知道对齐并确保它适合。我不会假装知道/理解您将用于将此信息转换为对齐保证的实际逻辑,但它确实存在且可供使用。

答案 4 :(得分:1)

据我所知,boost :: pool基于alexandrescu的“小对象分配器”,在他的“现代c ++设计”一书中解释过。我必须读书(因为你正在写这些东西也是为了学习)