在堆栈上分配对齐的内存,如_alloca

Allocate aligned memory on the stack like _alloca

本文关键字:alloca 内存 堆栈 分配 对齐      更新时间:2023-10-16

_alloca()的文档显示如下:

_alloca例程返回一个指向所分配空间的void指针,其保证被适当地对准以用于存储任何类型的对象

然而,这里说:

_alloca需要16字节对齐,此外还需要使用帧指针。

因此,在第一次引用中,他们似乎忘记了32字节对齐的AVX/AVX2类型,如__m256d

另一件让我困惑的事情是,第一页说_alloca()不推荐使用,而它建议使用一个可能从堆而不是堆栈分配内存的函数(这在我的多线程应用程序中是不可接受的)。

那么,有人能告诉我,是否有一些现代的(也许是新的C/C++标准?)对齐堆栈内存分配的方法吗?

澄清1:请不要提供要求数组大小为编译时间常数的解决方案。我的函数根据运行时参数值分配可变数量的数组项。

用_alloca()过度分配,然后手动对齐。像这样:

const int align = 32;
void *p =_alloca(n + align - 1);
__m256d *pm = (__m256d *)((((int_ptr_t)p + align - 1) / align) * align);

如有必要,用#define替换const

_alloca()当然不是处理堆栈对齐的标准或可移植方式。幸运的是,在C++11中我们得到了alignasstd::aligned_storage。这两种方法都不强迫你把任何东西放在堆里,所以它们应该适用于你的用例。例如,将结构数组与32字节边界对齐:

#include <type_traits>
struct bar { int member; /*...*/ };
void fun() {
std::aligned_storage<sizeof(bar), 32>::type array[16];
auto bar_array = reinterpret_cast<bar*>(array);
}

或者,如果您只想将堆栈上的单个变量与边界对齐:

void bun() {
alignas(32) bar b;
}

还可以使用alignof运算符来获取给定类型的对齐要求。

C++11引入了alignof运算符:

alignof表达式产生其操作数类型的对齐要求。

您可以按如下方式使用它:

struct s {};
typedef s __attribute__ ((aligned (64))) aligned_s;
std::cout << alignof(aligned_s); // Outputs: 64

注意:如果类型的对齐大于其大小,编译器将不允许您声明数组类型的数组(请参阅此处的更多信息):

错误:数组元素的对齐大于元素大小

但是,如果类型的对齐小于其大小,则可以安全分配阵列:

aligned_s arr[32];
-- OR --
constexpr size_t arr_size = 32;
aligned_s arr[arr_size];

支持VLA的编译器也将允许新定义的类型使用VLA。

"现代"方式是:

不要在堆栈上进行可变长度分配

在你的问题中——想要在堆上分配,但又不这么做——我假设你分配的内存可能超过了一些小的编译时常量。在这种情况下,您只需要使用alloca()调用来破坏堆栈。相反,使用线程安全的内存分配器。我相信GitHub上有这样的库(最坏的情况下,你可以用全局互斥来保护分配调用,尽管如果你需要很多互斥,这会很慢)。

另一方面,如果你事先知道分配大小的上限是多少——只需在线程本地存储中预先分配那么多内存;或者使用固定大小的本地数组(将在堆栈上分配)。