二、 字节对齐

2020-09-25  本文已影响0人  Mlqq

探索OC类的大小要先来说一下结构体,因为OC类底层都是以结构体的形式存在的。

1 结构体大小-字节对齐

我们先定义一下两个结构体:

//1、定义两个结构体
struct Mystruct1{
    char a;     //1字节
    double b;   //8字节
    int c;      //4字节
    short d;    //2字节
}Mystruct1;

struct Mystruct2{
    double b;   //8字节
    int c;      //4字节
    short d;    //2字节
    char a;     //1字节
}Mystruct2;

//计算 结构体占用的内存大小
NSLog(@"%lu-%lu",sizeof(Mystruct1),sizeof(Mystruct2));

一下是输出结果:

image.png 从结构体的成员来说都是一样的,就是顺序不一样而已,为什么大小就不一样呢?这个就是字节对齐导致的。

内存对齐规则

每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。在ios中,Xcode默认为#pragma pack(8),即8字节对齐

(1)数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第
一个数据成员放在offset0的地方,以后每个数据成员存储的起始位置要
从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,
结构体等)的整数倍开始(比如int4字节,则要从4的整数倍地址开始存
储。min(当前开始的位置mn)m=9 n=4 9 10 11 12

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

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

验证对齐规则

下表是各种数据类型在ios中的占用内存大小,根据对应类型来计算结构体中内存大小

image.png 根据上面的规则解释一下为什么Mystruct1Mystruct2两个结构体大小不一样
根据内存对齐规则计算MyStruct1的内存大小,详解过程如下:

根据内存对齐规则计算MyStruct2的内存大小,详解过程如下:

结构体套嵌结构体

我们在定义一个结构体3如下:

struct Mystruct3 {
    int c;
    struct Mystruct1 str;
    short d;
}Mystruct3;

我们来分析一下Mystruct3的大小:

看一下运行结果: image.png

2 OC类的字节对齐

alloc&init&new流程提到过alloc流程里面的三个重要的放方法: size = cls->instanceSize(extraBytes);obj = (id)calloc(1, size);obj->initInstanceIsa(cls, hasCxxDtor);,这里我们分析size = cls->instanceSize(extraBytes);这个方法。
从这个方法跟进去就是:

image.png 继续跟进去: image.png 继续进去: image.png 这里就是OC类对齐的方法:
static inline size_t align16(size_t x) {
    return (x + size_t(15)) & ~size_t(15);
}

这就是16字节对齐,也就是说OC类大小开辟的空间大小是16的倍数。这里就不验证了,感兴趣的朋友可以自己验证一下。

3 OC内存重排

我们先创建一个类MlqqObject,属性参考图中,创建是一个实力对象objc,然后对属性复制,然后打印objc的内存分布,如下图:

image.png 来分析一下内存情况:

6以后的字节都打印一下,都没有看到ageweight的值。其实ageweight的值就是在第28字节,我么把它拆为两部分分别打印:

image.png

正是ageweight的值,这就是系统对属性重排的结果。ageweight都是int类型,占4字节,两个int是8字节,正好可以用一个8字节来存存储,就没必要一个int也要占8字节。
height也是int类型,也是占4字节,为什么不是ageheight放在一起呢,我们改变一下属性声明的顺序

image.png

改变属性声明的顺序后,内存分布的顺序也改变了,现在第28字节存的是weightheight,第38字节存的是age,后面才是NSString类型。
另外同样是第28字节,也就是重排的字节,声明在前面的内存中在后面。weight声明在height前面,内存0x0000001300000011,前4个字节是height,后4个字节是weight,为了更好的说明,我们再增加多一点属性,按照下面方式:

image.png

内存重排总结:

上一篇 下一篇

猜你喜欢

热点阅读