注册
iOS

iOS 底层原理探索 之 结构体内存对齐


f9ef09d5e5f9408cabc965e2414e55b6~tplv-k3u1fbpfcp-zoom-crop-mark:1304:1304:1304:734.awebp


写在前面: iOS底层原理探究是本人在平时的开发和学习中不断积累的一段进阶之
路的。 记录我的不断探索之旅,希望能有帮助到各位读者朋友。

目录如下:

  1. iOS 底层原理探索之 alloc

以上内容的总结专栏


准备

Objective-C ,通常写作ObjC或OC,是扩充C的面向对象编程语言。它主要适用于Mac OS X 和 GNUstep者两个使用OpenStep标准的系统,而在NeXTSTEP和OpenStep中它更是基本语言。

GCC和Clang含Objective-C的编译器,Objective-C可以在GCC以及Clang运作的系统上编译。

我们平时开发用的Objective-C语言,编译后最终会转化成C/C++语言。

为什么要研究结构体的内存对齐呢? 因为作为一名iOS开发人员,随着对于底层的不断深入探究,我们都知道,所有的对象在底层中都是一个结构体。那么结构体的内存空间又会被系统分配多少空间,这个问题,值得我们一探究竟。

首先,从大神Cooci那里盗取了一张各数据类型占用的空间大小图片,作为今天探究结构体内存对齐原理的依据。

image.png

当我们创建一个对象的时候,我们并不需要过多的在意属性的顺序,因为系统会帮我们做优化处理。但是,在创建结构体的时候,就需要我们去分析了,因为这个时候系统并不会帮助我们做优化。

接下来,我们看下面两个结构体:

struct Struct1 {    
double a;
char b;
int c;
short d;
char e;
}struct1;

struct Struct2 {
double a;
int b;
char c;
short d;
char e;
}struct2;


两个结构体拥有的数据类型是相同的,按照图片中double 是8字节, char 是1字节, int 是4字节,short 是2字节, 那么 两个结构体应该是占 16字节的内存空间,也就是分配16字节空间即可,然而,我们看下面的结果:

    printf("%lu--%lu", sizeof(struct1), sizeof(struct2));
------------
24--16

那么,这就是有问题的了,两个拥有相同数据类型的结构体,被系统分配到的内存空间是不一样的,这是为什么呢?今天的重点就是这里,结构体的

内存对齐原则:

1:数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第
一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置
要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是
数组,结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址
开始存储。

2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从
其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,
b里有char,int ,double等元素,那b应该从8的整数倍开始存储)

3:收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员
的整数倍,不足的要补⻬。

那么,我们按照以上内存对齐原则再来分析下 struct1 和 struct2 :


struct Struct1 { /// 18 --> 24
double a; //8 [0 1 2 3 4 5 6 7]
char b; //1 [8 ]
int c; //4 [9 [12 13 14 15]
short d; //2 [16 17]
char e; //1 [18]
}struct1;


struct Struct2 { /// 16 --> 16
double a; //8 [0 1 2 3 4 5 6 7]
int b; //4 [8 9 10 11]
char c; //1 [ 12 ]
short d; //2 [14 15]
char e; // 1 [16]
}struct2;


接着,我们看下下面的结构体

struct Struct3 {    
double a;
int b;
char c;
short d;
int e;
struct Struct1 str;
}struct3;


打印输出结果为 48 ,分析如下:

    double a;           //8 [0 1 2 3 4 5 6 7]
int b; //4 [8 9 10 11]
char c; //1 [12]
short d; //2 [ 14 15 ]
int e; //4 [ 16 17 18 19]
struct Struct1 str; //24 [24 ... 47]

所以,struct3 大小为48。


猜想:内存对齐的收尾工作中的内部最大成员指的是什么的大小呢?

接下来我们来一一验证一下

struct LGStruct4 {          /// 40 --> 48 
double a; //8 [0 1 2 3 4 5 6 7]
int b; //4 [8 9 10 11]
char c; //1 [12]
short d; //2 [14 15]
int e; //4 [16 17 18 19]
struct Struct2 str; //16 [24 ... 39]
}struct4;

按照我对于内存对齐原则中收尾工作的理解, 最终的大小 应该是 Struct2 的 大小 16 的整数倍 也就是 48 才对。然而, 结果却是:

    NSLog(@"%lu", sizeof(struct4));
--------
SMObjcBuild[8076:213800] 40

对,是40你没有看错,这样的话,很显然,我理解的就是错误的, 结构体内部最大成员应该指的是这里的 double,那么我们接下来验证一下: 1、

struct Struct2 {    ///16
double a; //8 [0 1 2 3 4 5 6 7]
int b; //4 [8 9 10 11]
char c; //1 [ 12 ]
short d; //2 [14 15]
}struct2;

struct LGStruct4 { /// 24

short d; //2 [0 1]

struct Struct2 str; // 16 [8 ... 23]

}struct4;

结果是 :24


因为,结构体内部最大成员是 double也就是8;并不是按照 LGStruct4中的str长度为16的整数倍来计算,所以最后的结果是24。

总结

结构体内部最大成员指的是结构体内部的数据类型,所以,结构体内包含结构体的时候,并不是按照内部的结构体长度的整数倍来计算的哦。


0 个评论

要回复文章请先登录注册