内存布局
1
| clang++ -Xclang -fdump-record-layouts -c main.cpp
|
- 多态对象的起始是虚函数表。
- 按继承顺序排布各个类,声明顺序排布各个成员,需要结合对齐规则。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| struct BaseA { BaseA() = default; virtual ~BaseA() = default; void FuncA() {} virtual void testA() { printf("BaseA testA\n"); } int a; int b; }; struct BaseB { BaseB() = default; virtual ~BaseB() = default; void FuncB(){} virtual void testB() { printf("BaseB testB\n"); } int c; int d; }; struct Derive : public BaseA, public BaseB { virtual void testA() override { printf("Derive testA\n"); } virtual void testB() override { printf("Derive testB\n"); } };
*** Dumping AST Record Layout 0 | struct Derive 0 | struct BaseA (primary base) 0 | (BaseA vtable pointer) 8 | int a 12 | int b 16 | struct BaseB (base) 16 | (BaseB vtable pointer) 24 | int c 28 | int d | [sizeof=32, dsize=32, align=8, | nvsize=32, nvalign=8]
Vtable for 'Derive' (11 entries). 0 | offset_to_top (0) 1 | Derive RTTI -- (BaseA, 0) vtable address -- -- (Derive, 0) vtable address -- 2 | Derive::~Derive() [complete] 3 | Derive::~Derive() [deleting] 4 | void Derive::testA() 5 | void Derive::testB() 6 | offset_to_top (-16) 7 | Derive RTTI -- (BaseB, 16) vtable address -- 8 | Derive::~Derive() [complete] [this adjustment: -16 non-virtual] 9 | Derive::~Derive() [deleting] [this adjustment: -16 non-virtual] 10 | void Derive::testB() [this adjustment: -16 non-virtual]
|
一个小细节:虚析构函数占用了虚函数表中的两个entry
为什么要内存对齐?
- CPU效率,访存往往会取连续的一段(如64字节)进行cache
- CPU限制,比如只能以word(如4字节)为单位进行访存。此时非word的倍数就是未对齐访存,有些处理器直接不支持,而支持的处理器也需要更多条指令
- 并发的false sharing问题
pragma
指示编译器以特定对齐方式对齐结构体成员,其中对齐单位=min(n, 结构体成员的最大大小)
gcc默认n=4。
每个成员的偏移值都是min(对齐单位, 该成员大小)的整数倍,且整个结构体的大小也是对齐单位的整数倍。
1 2 3 4 5
| #pragma pack(n) struct A {
}; alignof(A);
|
attribute
1 2
| __attribute((packed)); __attribute((aligned(x)));
|
alignas
作用类似于__attribute((aligned(x)))