内存对齐规则
1:数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第
一个数据成员放在offset为0的地方(即首地址的位置),以后每个数据成员存储的起始位置要
从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,
结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址开始存
储。
2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从
其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b
里有char,int ,double等元素,那b应该从8的整数倍开始存储.)
3:收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大
成员的整数倍.不足的要补⻬。
上面的规则真书面化,看了几遍 翻一下
结构体或者联合 的第一个数据成员放在offset 为0 的地方(即首地址);
从第二个数据成员开始,存储的起始位置是该成员大小的整数倍(比如int为4字节,则该成员的存储位置的其实地址是4的整数倍。(取 默认对齐数 和该成员对齐数的较小值 )
结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)
最大对齐数就是对大的成员大小
struct WQPeople1{
char a; // 1 + 7
double b; // 8
int c; // 4
short d; // 2 + 2
}myPeople1;
struct WQPeople2{
double b; // 8
int c; // 4
char a; // 1
short d; // 2 + 1
};
WQPeople1 a 1位 b8位 > 8 所以 a 补 7位 b单独8位
c 4位 d 2位 < 8 所以补 2位
WQPeople2 b 8位 > 8
c 4位 a 1位 d 2位 < 8 所以补 1位
struct X1
{
char c1;
int i;
char c2;
};
/*
为什么是 12 ?
假设首地址为 px0; 0x7ffee2553170
char c1 1个字节 首地址为px0 使用1个字节但是占用4字节 符合偏移量为0的地方开始;占用4 是因为下个成员取4的整数倍
int i 4个字节, 地址为px0 + 4 占用4个字节 符合开始地址必须是该成员大小的整数倍
char c2 1 字节 地址为px0 + 8 1个字节
共9 个字节; 符合 总大小应该为最大成员
p pp
(X1) $5 = (c1 = 'a', i = 14, c2 = 'b')
61 00 00 00 0E 00 00 00 61 =》 16 * 6 + 1 = 97 E=》 14
62 00 00 00 00 00 00 00 61 =》98
*/
struct X2
{
char c1;
char c2;
int i;
};
/*
首地址 0x7ffee56ef168
61 62 00 00 0E 00 00 00
char c1; 从0 开始 占 1 字节
char c2; 大小为 1 故 从 1开始 占 1字节
int i; 大小为 4 字节 故 从4的倍数开始 从4 开始 占用 4个字节
最大对齐数是 4 一共使用了 1 + 1 + [2] + 4 = 8 8 是4的倍数 故占用8 个字节
最大对齐数是最大成员的对齐数,这个是前面算过的(成员大小和默认对齐数取小)
*/
struct X3
{
double d;
char c;
int i;
};
/*
0x7ffee7614158
CD CC CC CC CC CC 24 40
64 00 00 00 14 00 00 00 -> b 14
double d; 8
char c; 1 + [3]
int i; 从4的倍数开始 所以上面 补 3 占用 4个
共 8 + 1 +【3】 + 4 = 16 最大对齐数 min(默认对齐数 ,成员中自身最大对齐数) -》16
*/
str``uct X4
{
char c1;
struct X3 x3;
double d;
};
/*
61 00 00 00 00 00 00 00 a
CD CC CC CC CC CC 24 40 10.4
62 00 00 00 0E 00 00 00 b 14
33 33 33 33 33 33 25 40
struct X4 pp4 = {'a',{10.4,'b',14},10.6};
char c1; 1字节 +【7】
struct X3 x3; x3的最大对齐数是它min(内部成员变量的最大对齐数,默认成员对齐数) = 8 占用了 8 + 1+【3】 + 4 = 16
double d; 占用8个
共 1+ 【7】 + 16 + 8个 = 32个
*/
struct X1 pp = {'a',14,'b'};
printf("X1 == %lu", sizeof(struct X1));
struct X2 pp2 = {'a','d',20};
printf("X2 == %lu", sizeof(struct X2));
struct X3 pp3 = {10.4,'d',20};
struct X4 pp4 = {'a',{10.4,'b',14},10.6};
printf("X2 == %lu", sizeof(struct X2));
printf("X3 == %lu", sizeof(struct X3)); //16
printf("X4 == %lu", sizeof(struct X4));
pp 内存图
pp2
pp3
pp 4
对齐算法
_class_createInstanceFromZone
->
size_t size;
/// 设置开辟内存的大小
size = cls->instanceSize(extraBytes);
size_t instanceSize(size_t extraBytes) const {
...
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
/// 内存最少是16字节
if (size < 16) size = 16;
return size;
}
uint32_t alignedInstanceSize() const {
/// 字节对齐
return word_align(unalignedInstanceSize());
}
注意点class_getInstanceSize实际占用的大小 没有size < 16 size = 16;
NSLog(@"%zu--%zu",
class_getInstanceSize([person class]),
malloc_size((__bridge const void *)(person))
);
// 8 --16
size_t class_getInstanceSize(Class cls)
{
if (!cls) return 0;
return cls->alignedInstanceSize();
}
uint32_t alignedInstanceSize() const {
/// 字节对齐
return word_align(unalignedInstanceSize());
}
# define WORD_MASK 7UL
static inline size_t word_align(size_t x) {
return (x + WORD_MASK) & ~WORD_MASK;
}
#ifdef __LP64__
# define WORD_SHIFT 3UL
# define WORD_MASK 7UL
# define WORD_BITS 64
#else
# define WORD_SHIFT 2UL
# define WORD_MASK 3UL
# define WORD_BITS 32
#endif
return (x + WORD_MASK) & ~WORD_MASK;// 返回8的整数倍
/*
获取大于等于某一个数的最小8倍数 比如 15 -》 8 ; 16 - 》 16 ; 17 -》16
例子1: (8 + 7) & ~7
7 0000 0111
~7 1111 1000
15 &0000 1111
--------------------
0000 1000 = 8
例子2: ( 9 + 7) & ~7
7 0000 0111
~7 1111 1000
& 16 0001 0000
-----------------------
0001 0000 16
结论 (x + 2^n) & ~2^n -> m(m大于等于x 且是2^n的最小倍数)
//另外一种获取大于等于某一个数的最大的那个8的倍数
k = x >>3
q = <<3
15 0000 1111
0000 0001
0000 1000
8