简体   繁体   English

自定义堆栈分配器中的C ++内存对齐

[英]C++ Memory alignment in custom stack allocator

Usually data is aligned at power of two addresses depending on its size. 通常,数据根据其大小以两个地址的幂对齐。

How should I align a struct or class with size of 20 bytes or another non-power-of-two size? 我应该如何对齐大小为20字节或另一种非二次幂大小的结构或类?

I'm creating a custom stack allocator so I guess that the compiler wont align data for me since I'm working with a continuous block of memory. 我正在创建一个自定义堆栈分配器,所以我猜编译器不会为我调整数据,因为我正在使用连续的内存块。

Some more context: 更多背景:

I have an Allocator class that uses malloc() to allocate a large amount of data. 我有一个Allocator类,它使用malloc()来分配大量数据。 Then I use void* allocate(U32 size_of_object) method to return the pointer that where I can store whether objects I need to store. 然后我使用void * allocate(U32 size_of_object)方法返回指针,我可以在哪里存储我需要存储的对象。 This way all objects are stored in the same region of memory and it will hopefully fit in the cache reducing cache misses. 这样,所有对象都存储在相同的内存区域中,并且它有望适合缓存减少缓存未命中。

Although the compiler (or interpreter) normally allocates individual data items on aligned boundaries, data structures often have members with different alignment requirements. 虽然编译器(或解释器)通常在对齐的边界上分配单独的数据项,但数据结构通常具有具有不同对齐要求的成员。 To maintain proper alignment the translator normally inserts additional unnamed data members so that each member is properly aligned. 为了保持正确的对齐,翻译器通常会插入其他未命名的数据成员,以便每个成员都正确对齐。 In addition the data structure as a whole may be padded with a final unnamed member. 此外,整个数据结构可以用最终未命名的成员填充。 This allows each member of an array of structures to be properly aligned. 这允许结构阵列的每个成员正确对齐。 http://en.wikipedia.org/wiki/Data_structure_alignment#Typical_alignment_of_C_structs_on_x86 http://en.wikipedia.org/wiki/Data_structure_alignment#Typical_alignment_of_C_structs_on_x86

This says that the compiler takes care of it for you, 99.9% of the time. 这表示编译器会为您处理它,99.9%的时间。 As for how to force an object to align a specific way, that is compiler specific, and only works in certain circumstances. 至于如何强制对象对齐特定方式,这是特定于编译器的,并且仅在某些情况下有效。

MSVC: http://msdn.microsoft.com/en-us/library/83ythb65.aspx MSVC: http//msdn.microsoft.com/en-us/library/83ythb65.aspx

__declspec(align(20)) 
struct S{ int a, b, c, d; };
//must be less than or equal to 20 bytes

GCC: http://gcc.gnu.org/onlinedocs/gcc-3.4.0/gcc/Type-Attributes.html 海湾合作委员会: http//gcc.gnu.org/onlinedocs/gcc-3.4.0/gcc/Type-Attributes.html

struct S{ int a, b, c, d; } 
__attribute__ ((aligned (20)));

I don't know of a cross-platform way (including macros!) to do this, but there's probably neat macro somewhere. 我不知道这样做的跨平台方式(包括宏!),但在某处可能有一些整洁的宏。

C++11 has the alignof operator specifically for this purpose. C ++ 11专门为此目的使用了alignof运算符。 Don't use any of the tricks mentioned in other posts, as they all have edge cases or may fail for certain compiler optimisations. 不要使用其他帖子中提到的任何技巧,因为它们都有边缘情况,或者可能因某些编译器优化而失败。 The alignof operator is implemented by the compiler and knows the exact alignment being used. alignof运算符由编译器实现,并且知道正在使用的精确对齐。

See this description of c++11's new alignof operator 请参阅c ++ 11的新alignof运算符的此描述

除非您想直接访问内存,或者在内存块中挤压最大数据,否则您不必担心对齐 - 编译器会为您解决这个问题。

Due to the way processor data buses work, what you want to avoid is 'mis-aligned' access. 由于处理器数据总线的工作方式,您要避免的是“错误对齐”访问。 Usually you can read a 32 bit value in a single access from addresses which are multiples of four; 通常,您可以从一次访问中读取32位值,该地址是四的倍数; if you try to read it from an address that's not such a multiple, the CPU may have to grab it in two or more pieces. 如果你试图从一个不是这么多的地址读取它,CPU可能必须抓住两个或多个部分。 So if you're really worrying about things at this level of detail, what you need to be concerned about is not so much the overall struct, as the pieces within it. 所以,如果你真的在这个细节层面上担心事情,那么你需要关注的不是整体结构,而是整体结构。 You'll find that compilers will frequently pad out structures with dummy bytes to ensure aligned access, unless you specifically force them not to with a pragma. 您会发现编译器会经常使用虚拟字节填充结构以确保对齐访问,除非您特别强制它们不使用pragma。

Since you've now added that you actually want to write your own allocator, the answer is straight-forward: Simply ensure that your allocator returns a pointer whose value is a multiple of the requested size. 由于您现在已经添加了实际上想要编写自己的分配器,因此答案是直截了当的:只需确保您的分配器返回一个值为所请求大小的倍数的指针。 The object's size itself will already come suitably adjusted (via internal padding) so that all member objects themselves are properly aligned, so if you request sizeof(T) bytes, all your allocator needs to do is to return a pointer whose value is divisible by sizeof(T) . 对象的大小本身已经适当调整(通过内部填充),以便所有成员对象本身都正确对齐,所以如果你请求sizeof(T)字节,你的所有分配器需要做的是返回一个值可被整除的指针sizeof(T)

If your object does indeed have size 20 (as reported by sizeof ), then you have nothing further to worry about. 如果您的对象确实具有大小为20(由sizeof报告),那么您无需进一步担心。 (On a 64-bit platform, the object would probably be padded to 24 bytes.) (在64位平台上,对象可能会填充到24个字节。)

Update: In fact, as I only now came to realize, strictly speaking you only need to ensure that the pointer is aligned, recursively, for the largest member of your type. 更新:事实上,正如我现在才意识到的那样,严格来说,您只需要确保指针以递归方式对齐您的类型中最大的成员 That may be more efficient, but aligning to the size of the entire type is definitely not getting it wrong. 这可能更有效,但是与整个类型的大小对齐绝对不会错。

How should I align a struct or class with size of 20 bytes or another non-power-of-two size? 我应该如何对齐大小为20字节或另一种非二次幂大小的结构或类?

Alignment is CPU-specific, so there is no answer to this question without, at least, knowing the target CPU. 对齐是特定于CPU的,因此至少在不了解目标CPU的情况下,对此问题没有答案。

Generally speaking, alignment isn't something that you have to worry about; 一般来说,对齐不是你必须担心的事情; your compiler will have the rules implemented for you. 您的编译器将为您实现规则。 It does come up once in a while, like when writing an allocator. 它偶尔出现,就像编写分配器一样。 The classic solution is discussed in The C Programming Language (K&R): use the worst possible alignment. C编程语言 (K&R)中讨论了经典的解决方案:使用最差的对齐方式。 malloc does this, although it's phrased as , "the pointer returned if the allocation succeeds shall be suitably aligned so that it may be assigned to a pointer to any type of object." malloc执行此操作,尽管它的措辞为 “,如果分配成功,则返回的指针应适当对齐,以便可以将其指定给指向任何类型对象的指针。”

The way to do that is to use a union (the elements of a union are all allocated at the union 's base address, and the union must therefore be aligned in such a way that each element could exist at that address; ie, the union 's alignment will be the same as the alignment of the element with the strictest rules): 做到这一点的方法是使用一个union (A的元素union全部分配在union的基地址,并且union因此必须以这样的方式排列,每个元件可以在该地址存在;即, union的对齐方式与元素与最严格规则的对齐方式相同):

typedef Align long;
union header {
    // the inner struct has the important bookeeping info
    struct {
        unsigned size;
        header* next; 
    } s;
    // the align member only exists to make sure header_t's are always allocated
    // using the alignment of a long, which is probably the worst alignment
    // for the target architecture ("worst" == "strictest," something that meets
    // the worst alignment will also meet all better alignment requirements)
    Align align;
};

Memory is allocated by creating an array (using somthing like sbrk() ) of header s large enough to satisfy the request, plus one additional header element that actually contains the bookkeeping information. 通过创建一个足以满足请求的header s的数组(使用像sbrk() )来分配内存,另外还有一个实际包含簿记信息的额外header元素。 If the array is called arry , the bookkeeping information is at arry[0] , while the pointer returned points at arry[1] (the next element is meant for walking the free list). 如果数组被称为arry ,则簿记信息在arry[0] ,而指针返回arry[1]处的点( next元素用于遍历空闲列表)。

This works, but can lead to wasted space ("In Sun's HotSpot JVM, object storage is aligned to the nearest 64-bit boundary"). 这可行,但可能导致浪费的空间 (“在Sun的HotSpot JVM中,对象存储与最近的64位边界对齐”)。 I'm aware of a better approach that tries to get a type-specific alignment instead of "the alignment that will work for anything." 我知道一种更好的方法 ,试图获得特定于类型的对齐,而不是“对任何东西都有效的对齐”。

Compilers also often have compiler-specific commands. 编译器通常还具有特定于编译器的命令。 They aren't standard, and they require that you know the correct alignment requirements for the types in question. 它们不是标准的,它们要求您知道相关类型的正确对齐要求。 I would avoid them. 我会避免他们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM