C++ 获得对齐内存的最佳跨平台方法
下面是我通常用来与VisualStudio和GCC对齐内存的代码C++ 获得对齐内存的最佳跨平台方法,c++,c,performance,sse,memory-alignment,C++,C,Performance,Sse,Memory Alignment,下面是我通常用来与VisualStudio和GCC对齐内存的代码 inline void* aligned_malloc(size_t size, size_t align) { void *result; #ifdef _MSC_VER result = _aligned_malloc(size, align); #else if(posix_memalign(&result, align, size)) result = 0; #
inline void* aligned_malloc(size_t size, size_t align) {
void *result;
#ifdef _MSC_VER
result = _aligned_malloc(size, align);
#else
if(posix_memalign(&result, align, size)) result = 0;
#endif
return result;
}
inline void aligned_free(void *ptr) {
#ifdef _MSC_VER
_aligned_free(ptr);
#else
free(ptr);
#endif
}
这个代码一般可以吗?我还看到人们使用\u-mm\u-malloc
,\u-mm\u-free
。在大多数情况下,我需要对齐内存,它使用SSE/AVX。我可以一般使用这些函数吗?这将使我的代码简单得多
最后,很容易创建我自己的函数来对齐内存(见下文)。那么,为什么有这么多不同的通用函数来获得对齐内存(其中许多函数只在一个平台上工作)
此代码执行16字节对齐
float* array = (float*)malloc(SIZE*sizeof(float)+15);
// find the aligned position
// and use this pointer to read or write data into array
float* alignedArray = (float*)(((unsigned long)array + 15) & (~0x0F));
// dellocate memory original "array", NOT alignedArray
free(array);
array = alignedArray = 0;
见:和
编辑:
如果有人关心的话,我是从Eigen(Eigen/src/Core/util/Memory.h)中得到对齐的_malloc()函数的
编辑:
我刚刚发现MinGW的
posix_memalign
没有定义。但是,<>代码> MyMaMalc 对于Visual Studio 2012、GCC、MIWW和英特尔C++编译器都是有效的,因此它似乎是最方便的解决方案。它还需要使用自己的\u mm\u free
函数,尽管在某些实现中,您可以将指针从\u mm\u malloc
传递到标准free
/delete
您提出的第一个函数确实可以正常工作
您的“自制”功能也可以工作,但有一个缺点,即如果值已对齐,则只会浪费15个字节。有时可能并不重要,但操作系统很可能能够提供正确分配的内存,而不会产生任何浪费(如果需要将其对齐到256或4096字节,则添加“对齐-1”字节可能会浪费大量内存) 只要你可以调用一个特殊函数来进行释放,你的方法就可以了。不过,我会用另一种方法来处理您的
#ifdef
s:从指定的标准选项开始,然后回到特定于平台的选项。比如说
\uuuuu STDC\u VERSION\uuuuu>=201112L
使用对齐的\u alloc
\u POSIX\u VERSION>=200112L
使用POSIX\u memalign
\u MSC\u VER
,请使用Windows工具malloc
/free
并禁用SSE/AVX代码即可如果您希望能够将分配的指针传递到
free
,问题就更难了;这在所有标准接口上都有效,但在Windows上无效,并且不一定与某些类unix系统的遗留memalign
函数配合使用。如果编译器支持,C++11会添加一个std::align
函数来进行运行时指针对齐。您可以像这样实现自己的malloc/free(未经测试):
模板
空*对齐的\u malloc(标准::大小\u t大小)
{
std::size\u t space=size+(Align-1);
void*ptr=malloc(空间+sizeof(void*));
作废*原件_ptr=ptr;
char*ptr_字节=静态_转换(ptr);
ptr_bytes+=sizeof(void*);
ptr=静态_转换(ptr_字节);
ptr=std::align(对齐、大小、ptr、空间);
ptr_字节=静态_转换(ptr);
ptr_字节-=sizeof(void*);
std::memcpy(ptr_字节、原始ptr、sizeof(void*);
返回ptr;
}
无空隙对齐(无空隙*ptr)
{
void*ptr_字节=静态_转换(ptr);
ptr_字节-=sizeof(void*);
作废*原件;
std::memcpy(&original_ptr,ptr_字节,sizeof(void*));
标准::免费(原件);
}
然后不必保留原始指针值来释放它。我不确定这是否是100%便携的,但如果不是,我希望有人会纠正我 这是我的2美分:
temp = new unsigned char*[num];
AlignedBuffers = new unsigned char*[num];
for (int i = 0; i<num; i++)
{
temp[i] = new unsigned char[bufferSize +15];
AlignedBuffers[i] = reinterpret_cast<unsigned char*>((reinterpret_cast<size_t>
(temp[i% num]) + 15) & ~15);// 16 bit alignment in preperation for SSE
}
temp=新的无符号字符*[num];
AlignedBuffers=新的无符号字符*[num];
对于(inti=0;i这里是一个固定的user2093113示例,直接代码不是为我生成的(void*未知大小)。我还将它放在一个模板类中,覆盖操作符new/delete,这样您就不必进行分配并调用placement new
#include <memory>
template<std::size_t Alignment>
class Aligned
{
public:
void* operator new(std::size_t size)
{
std::size_t space = size + (Alignment - 1);
void *ptr = malloc(space + sizeof(void*));
void *original_ptr = ptr;
char *ptr_bytes = static_cast<char*>(ptr);
ptr_bytes += sizeof(void*);
ptr = static_cast<void*>(ptr_bytes);
ptr = std::align(Alignment, size, ptr, space);
ptr_bytes = static_cast<char*>(ptr);
ptr_bytes -= sizeof(void*);
std::memcpy(ptr_bytes, &original_ptr, sizeof(void*));
return ptr;
}
void operator delete(void* ptr)
{
char *ptr_bytes = static_cast<char*>(ptr);
ptr_bytes -= sizeof(void*);
void *original_ptr;
std::memcpy(&original_ptr, ptr_bytes, sizeof(void*));
std::free(original_ptr);
}
};
#包括
模板
类对齐
{
公众:
void*运算符新(标准::大小\u t大小)
{
std::size\u t space=size+(对齐-1);
void*ptr=malloc(空间+sizeof(void*));
作废*原件_ptr=ptr;
char*ptr_字节=静态_转换(ptr);
ptr_bytes+=sizeof(void*);
ptr=静态_转换(ptr_字节);
ptr=标准::对齐(对齐、大小、ptr、空间);
ptr_字节=静态_转换(ptr);
ptr_字节-=sizeof(void*);
std::memcpy(ptr_字节和原始ptr,sizeof(void*);
返回ptr;
}
void操作符删除(void*ptr)
{
char*ptr_字节=静态_转换(ptr);
ptr_字节-=sizeof(void*);
作废*原件;
std::memcpy(&original_ptr,ptr_字节,sizeof(void*));
标准::免费(原件);
}
};
像这样使用它:
class Camera : public Aligned<16>
{
};
class摄像头:公共对齐
{
};
还没有测试这段代码的跨平台性。但是关于_mm_malloc呢?如果我使用SSE/AVX,通常使用它可以吗?因此,即使我没有使用SSE/AVX,为什么不使用它呢?如果编译器支持_mm_malloc(),那么这也是一个有效的解决方案。您需要使用_mm_free()
也是。当然,您可以使用\u-mm\u-malloc()
进行任何内存分配-但当然,小的分配会比“通常”浪费更多的空间。好的,我想我将开始使用_-mm\u-malloc()和_-mm\u-free()。至少在这样的情况下,当我需要对齐内存时,答案是正确的。这使代码简单得多。虽然地址的无符号long
强制转换在实践中可能有效,但它可能无法在ILP32/LP64/LLP64(win64)之间移植数据模型。请参阅下面的“我的固定版本”。通过在void*上执行指针运算修复了编译器错误,并且对齐的\u malloc中的memcpy现在可以正确复制该值。即使对齐的分配器可用,此版本也总是浪费空间。-1.您可以通过使用一条语句简化delete
:if(ptr)std::free(static\u cast(ptr)[-1]);
a
class Camera : public Aligned<16>
{
};