开辟空间 - 字节对齐 + 内存对齐

一、字节对齐

1、为什么要进行字节对齐处理呢?

性能,快,以空间换取时间。

可以想象 2 个场景,场景 1:当我们的 CPU 去读取内存时,每次读取的大小如果是不确定的 (8、7、3、9… …),那么除非每次读取都要重新改变自己的读取方式否则读取的数据就会读错到其他数据上去。

场景 2,如果我们所存储的对象以固定的大小存储时,8/16,那么读取数据时,只需要按部就班去取 不必反复改变读取方式。

场景对比,自然是场景 2 更快捷方便。

2、Apple 的 16 字节对齐算法

Apple 的 objc 最新源码中目前是 16 字节对齐,在此之前是 8 字节对齐 (注意! 真正的对象内存大小仍是 8 字节对齐的,后面会分析的)。代码如下:

1
2
3
static inline size_t align16(size_t x) {
return (x + size_t(15)) & ~size_t(15);
}

算法流程如下图:–> 16 后抹零

3、验证

运行源码 demo:

如上图,MyPerson 有 3 个属性,+ isa = 4*8 = 32

下图情况:

此时,好像有 2 个问题,问题 001:我们每次都给对象 16 字节的对齐处理,未使用的空间岂不浪费了吗?还有打印时,问题 002:数据存储的顺序为什么和我们代码不一致呢?后面继续探索…

二、对象的大小

运行下图代码,MyPerson 中有 5 个属性 (有一个继承来的 isa):

结果分析

3.1)sizeof():类型大小. –> 例:sizeof(int)-4 / sizeof(double)-8 –>    sizeof(person)->person 类型 (MyPerson *) 指针 8

3.2)class_getInstanceSize()

对象的真正需要的内存大小 40 –> 8 字节对齐;

objc 源码:–> 8 字节对齐: (x + 7) & (7 取反) –> 算法和上面 16 字节对齐一样

3.3)开辟内存大小:malloc 源码分析

系统会开辟空间 48 –> 16 字节对齐,使之有更大的容错空间

malloc –> 16 字节对齐算法:

二、字节对齐会造成严重的内存空间浪费问题吗?

1、空间浪费了吗?

我们给 MyPerson 类添加 2 个 char 类型的 a1 a2,如下图,运行:

通过以上,我们可以得出,同一个地址中存了 3 个值,系统并不会一味的对所有对象都分配相同空间,它对内存是做了优化使用的。

2、内存对齐 

内存对齐原则

  1. 数据成员对齐规则:

  结构体 (struct) 的数据成员,第一个数据从 0 的位置开始存放,后面数据依次存。每个成员存放的起始位置 必须是这个成员的大小的 整数倍

  结构体作为成员,结构体 s2 作为 结构体 s 的成员,s2 的存储起始位置 应该是 s2 内部最大的成员大小的整数倍。

2、整个结构体大小

  结构体的总大小 (sizeof()),必须是结构体内部最大成员的整数倍,不足的补齐。

结构体内存对齐:

示例 2 则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct MyStruct1 {
double a; // 8 (0-7)
char b; // 1 [8 1] (8)
int c; // 4 [9 4] 9... -->大于94的倍数:12 --> (12 13 14 15)
short d; // 2 [16 2] (16 17)
}struct1;
// 内部需要的大小为: 17
// 最大属性 : 8
// 结构体大小需要是 其内部最大属性 的整数倍: 大于178的倍数 --> 24

//
// 15 --> 16
struct MyStruct2 {
double a; //8 (0-7)
int b; //4 (8 9 10 11)
char c; //1 (12)
short d; //2 13 (14 15) - 16
}struct2;

我们可以发现,上面 2 个结构体内部成员是一样的,只是顺序不同。但是 1 比 2 多占用 24-16=8 字节的内存 –> 浪费了呀??

–> 苹果系统做了优化,进行了 属性重排 –> 上面问题 002 的答案可知

注意:结构体不存在苹果的这个优化的,不同顺序大小不同。

调试命令地址: GDB to LLDB command map

不同数据类型字节大小:

x 的使用 读取内存

x /nuf

n 表示要显示的内存单元的个数

-----------------------------------------

u 表示一个地址单元的长度:

b 表示单字节

h 表示双字节

w 表示四字节

g 表示八字节

-----------------------------------------

f 表示显示方式, 可取如下值:

x 按十六进制格式显示变量

d 按十进制格式显示变量

u 按十进制格式显示无符号整型

o 按八进制格式显示变量

t 按二进制格式显示变量

a 按十六进制格式显示变量

i 指令地址格式

c 按字符格式显示变量

f 按浮点数格式显示变量


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!