malloc如何理解alignment?

从这里摘录

pw = (widget *)malloc(sizeof(widget)); 

分配原始存储。 实际上,malloc调用分配的存储空间足够大,并且适合于保存types小部件的对象

他还说,从草药口服中可以看到快速的药物 ,他说:

alignment 。 任何内存alignment。 任何通过new或mallocdynamic分配的内存都可以保证为任何types的对象正确alignment ,但是dynamic分配的缓冲区没有这种保证

我对此很好奇,malloc如何知道自定义types的alignment方式?

alignment要求是recursion的:任何struct的alignment只是其任何成员的最大alignment,这是recursion理解的。

例如,假设每个基本types的alignment都等于它的大小(通常这不总是正确的), struct X { int; char; double; } struct X { int; char; double; } struct X { int; char; double; }具有double的alignment方式,它将被填充为double的倍数(例如4(int),1(char),3(padding),8(double))。 struct Y { int; X; float; } struct Y { int; X; float; } X的排列是最大的,并且等于double的alignment,并且相应地布置Y :4(int),4(padding),16(X),4(float),4(padding) 。

(所有数字都只是示例,可能在您的机器上有所不同。)

因此,把它分解成基本types,我们只需要知道一些基本的配合,其中有一个最为知名的。 C ++甚至定义了一个typesmaxalign_t (我认为)其alignment最大的alignment。

所有的malloc()需要做的是select一个地址这个值的倍数。

我认为,香草萨特报价中最相关的部分是我用粗体标出的部分:

对准。 任何内存alignment。 任何通过new或mallocdynamic分配的内存都可以保证为任何types的对象正确alignment,但是dynamic分配的缓冲区没有这种保证

它不需要知道你想要什么types,因为它可以alignment任何types。 在任何给定的系统上,最大的alignment尺寸是必要的或有意义的; 例如,具有四字节字的系统可能最多具有四字节alignment。

malloc(3)手册也清楚地表明了这一点:

malloc()calloc()函数返回一个指向已分配内存的指针,该内存适合于任何types的variables

malloc()可以使用的唯一信息是传递给它的请求的大小。 一般来说,它可能会做一些事情,例如将传递的大小舍入到两个最接近的更大(或相等)的幂,并根据该值alignment内存。 alignment值也可能有一个上限,比如8个字节。

以上是一个假设的讨论,实际的实现取决于您使用的机器体系结构和运行时库。 也许你的malloc()总是返回8个字节alignment的块,它永远不会做任何不同的事情。

1)alignment所有路线的最小公倍数。 例如,如果整数需要4个字节alignment,但是指针需要8个,则将所有内容分配到8个字节alignment。 这会导致一切都alignment。

2)使用size参数来确定正确的alignment。 对于小尺寸你可以推断出types,比如malloc(1) (假设其他types的尺寸不是1)总是一个字符。 C ++ new有types安全的好处,所以总是可以用这种方式做出alignment的决定。

在C ++ 11之前,alignment的处理相当简单,通过使用最大的alignment方式,其中确切的值是未知的,malloc / calloc仍然以这种方式工作。 这意味着malloc分配正确alignment任何types。

错误的alignment可能导致根据标准的未定义的行为,但我已经看到x86编译器是慷慨的,只惩罚与较低的性能。

请注意,您也可以通过编译器选项或指令调整alignment方式。 (例如VisualStudio的编译包)。

但是,当涉及到放置新的 ,然后C + + 11给我们带来了新的关键字,称为alignmentalignas。 下面是一些代码,它显示了编译器最大alignment大于1的效果。下面的第一个放置是自动的,但不是第二个。

 #include <iostream> #include <malloc.h> using namespace std; int main() { struct A { char c; }; struct B { int i; char c; }; unsigned char * buffer = (unsigned char *)malloc(1000000); long mp = (long)buffer; // First placment new long alignofA = alignof(A) - 1; cout << "alignment of A: " << std::hex << (alignofA + 1) << endl; cout << "placement address before alignment: " << std::hex << mp << endl; if (mp&alignofA) { mp |= alignofA; ++mp; } cout << "placement address after alignment : " << std::hex <<mp << endl; A * a = new((unsigned char *)mp)A; mp += sizeof(A); // Second placment new long alignofB = alignof(B) - 1; cout << "alignment of B: " << std::hex << (alignofB + 1) << endl; cout << "placement address before alignment: " << std::hex << mp << endl; if (mp&alignofB) { mp |= alignofB; ++mp; } cout << "placement address after alignment : " << std::hex << mp << endl; B * b = new((unsigned char *)mp)B; mp += sizeof(B); } 

我猜这个代码的性能可以通过一些按位操作来改进。

编辑:取代昂贵的模运算与按位运算。 仍然希望有人发现更快。