【问题标题】:Dynamic aligned memory allocation in C++11C++11 中的动态对齐内存分配
【发布时间】:2011-08-07 16:18:48
【问题描述】:

Windows 上的posix_memalign_aligned_malloc 允许动态分配对齐的内存块。 C ++ 11中有类似的东西吗?据我所知,alignas 关键字仅适用于静态分配的对象。

【问题讨论】:

  • 对齐是指顺序吗?如果是,则使用new 运算符和[] 组合分配的内存是动态对齐的。
  • @Blindy:我不会说“相反”。更像“正交”?
  • 对齐是指地址模指定值为零。例如调用 posix_memalign(&ptr, 32, 1000) 保证在 ptr 中返回的地址可以被 32 整除。我需要它来在缓存行边界分配对象以避免错误共享。
  • 恐怕没有标准的 C++ 分配器支持任意对齐。您必须使用特定于平台的分配 API。但是,如果您将它与我给您的构造函数/析构函数的任意内存示例结合使用,这应该不是什么大问题。
  • C++17 将添加为动态分配的对象指定“自定义”/过度对齐的功能:open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3396.htm 最佳答案中提到的这个提议已被即将发布的标准接受。跨度>

标签: c++ c++11


【解决方案1】:

这取决于您需要什么对齐方式。对于 alignof(std::max_align_t) 的任何内容,new 按照 n3242 3.7.4.1/2 工作:

返回的指针应适当对齐,以便它可以 转换为具有基本的任何完整对象类型的指针 对齐要求

std::max_align_t 是一个完整的对象类型,具有最严格的基本对齐方式。

请注意,charunsigned char 而不是 signed char 的数组分配在 5.3.4/10 中有不同的规则:

对于 char 和 unsigned char 的数组,结果之间的差异 新表达式和分配返回的地址 函数应是最严格基本函数的整数倍 大小为 no 的任何对象类型的对齐要求 (3.11) 大于正在创建的数组的大小。

所以new char[1]; 的对齐方式可以是 1。

至于分配对齐大于alignof(std::max_align_t) 的内存,C++11 没有提供直接的方法来做到这一点。唯一可靠的方法是至少分配size + alignment 字节并使用std::align 在此缓冲区中获得正确对齐的位置。

这会浪费大量内存,因此如果您需要大量内存,您可以创建一个分配器,为所有内存分配足够大的块并在其上使用 std::align。然后,您的开销将在所有分配中摊销。

您的另一个选择是等待http://open-std.org/JTC1/SC22/WG21/docs/papers/2012/n3396.htm 使其成为标准。

就我个人而言,我只会在操作系统提供的 API 上编写一个抽象层来分配对齐的内存。

【讨论】:

    【解决方案2】:

    您可以使用 posix_memalign/_aligned_malloc 分配一块内存,然后使用特殊的“new”运算符语法来初始化该内存区域中的对象。像这样的:

    // Allocate raw memory for a Foo object.
    void *mem;
    size_t alignment = 0x1000;
    size_t size = ?;
    posix_memalign(&mem, alignment, size);
    // Call the constructor on the allocated memory.
    Foo *foo = new (mem) Foo(...);
    
    // Now you have a useable object.
    foo->some_method();
    
    // Call destructor without freeing object memory.
    foo->~Foo();
    // Free raw memory.
    free(foo);
    

    【讨论】:

    • 谢谢,对。我想知道的是 C++11 中是否有 posix_memalign 和 _aligned_malloc 的可移植替代品?
    • 根据标准mallocnew 应该可以工作。 _aligned_malloc 是因为 MS/Intel 引入了过度对齐的类型并遇到了问题。而不是修复malloc,并冒着破坏旧代码的风险,我们得到了_aligned_malloc
    • malloc 不支持 在任意大小上对齐,这可能是 user882903 想要的。
    【解决方案3】:

    看看std::aligned_storagealignas() 运算符。它们是 C++11 的一部分,似乎正是您正在寻找的。​​p>

    【讨论】:

    • 30.9.7.6p2:“是否支持任何扩展对齐由实现定义”参考std::aligned_storage。所以这也不是便携式的。
    • Stativ_Assert 所需的对齐可用。
    【解决方案4】:

    C++03 和 C++0x 有operator new

    new Tnew T[] 保证为 T 类型的对象返回正确对齐的内存。

    new char[]new signed char[]new unsigned char[] 保证为 any 对象返回正确对齐的内存,以便您可以在其上使用新位置。

    【讨论】:

    • 这些不适用于“任何”对象。例如,一个必须在页面边界分配的对象:当然没有 C++ 实现将所有分配对齐到 4096 字节边界。它保证支持任何标准的 C++ 原始类型(双精度通常是最严格的类型),但 PC 上的大多数编译器/运行时不支持对齐 SSE 类型的对齐要求(例如 16 字节对齐)。运算符 new 不对其所使用的类型进行对齐(或者实际上是任何元数据)这一事实是该语言的一个巨大缺陷。
    • 标准实际上所说的是“任何具有基本对齐要求的对象类型”,它肯定不符合 ANY 对象。
    • @SeanMiddleditch:实际上,它至少是任何内置类型。对于支持的最小对齐方式,请检查std::max_align_t 类型,因为std::malloc 保证返回至少与该对齐方式对齐的内存。实现可以随意返回更高的对齐方式。
    【解决方案5】:

    对于在堆上分配的对齐内存,我使用来自http://code.google.com/p/c-plus/source/browse/src/util.h#57 的 align() 实现,因为我的 gcc4.8 似乎不支持它。这是一个示例代码:

    typedef float TItem;
    static const int SIZE = 100;
    static const int ALIGNMENT = 16;
    
    // allocate heap storage larger then SIZE
    TItem* storage = new TItem[SIZE + (ALIGNMENT / sizeof(TItem))];
    void* storage_ptr = (void*)storage;
    size_t storage_size = sizeof(TItem) * (SIZE + 1);
    // aligned_array should be properly aligned
    TItem* aligned_array = (TItem*) align(MEM_ALIGNMENT, sizeof(TItem) * SIZE, storage_ptr, storage_size);
    if (!aligned_array) { throw std::bad_alloc(); }
    

    【讨论】:

      【解决方案6】:

      英特尔的TBB 提供了一个便携式cache_aligned_allocator,我认为您可能正在寻找它。

      【讨论】:

        【解决方案7】:

        C++ 标准始终保证从堆分配中任何对象的适当对齐 - 即,

        template<typename T> T* func() {
            char* buf = new char[sizeof(T)];
            return new(buf) T();
        }
        

        保证不会因为对齐原因而失败。

        【讨论】:

        • 大声笑,我们在同一秒回答了完全相同的问题 :)
        • 对不起,我认为我的问题不够精确。我想像 posix_memalign 一样明确指定边界。问的原因是我想在不同的缓存行分配小对象以避免错误共享。
        • 我不相信你能做到。您可以手动填充大小并分配更大的结构。
        • 这个答案是错误的,分配函数只支持对齐要求不比alignof(std::max_align_t)更严格的对象。请参见 3.7.4.1p2(或 5.3.4p10)和 3.11p2。也就是说,对象必须具有“基本对齐”。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-03-11
        • 2018-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-07
        相关资源
        最近更新 更多