结构体的内存对齐

2020-09-12  本文已影响0人  Bel李玉

在计算机系统中,为方便,快速的从内存中读取内存值,要求内存中的变量值需要按照一定的规则进行排放,在这篇文章中我们一起讨论结构体中的内存对齐。

内存对齐原则:

分析:

单个结构体

我们通过探讨下面两个结构体的内存分布,来探讨该问题

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

![内存对齐2.png](https://img.haomeiwen.com/i1891462/460d8737b79e80e6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


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

我们假设从内存为 0的位置开始存储

对于MyStruct1而言:

MyStruct1结构体的内存分布如下图所示,白色区域为填充区域,有颜色的地方为存放变量的区域。根据原则3结构体的大小为最大成员变量的整数倍原则,我们可以看出,其大小为 24.

内存对齐1.png

对于Mystruct2而言:

下图为Mystruct2的内存分布,我们可以看出 Mystruct2的内存大小为 16

内存对齐2.png

⚠️⚠️⚠️我们通过上面两个例子,来讲解结构体的内存对齐原理,我们可以看出,当结构体的成员一样时,其占用的内存大小并不一致,其内存大小与成员的排列顺序有关系

结构体嵌套

为了分析结构体嵌套里面的内存分布,我们定义如下

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

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

}MyStruct3;

MyStruct3中嵌套了 Mystruct2

根据以上分析,我们可以得到,MyStruct3占用了 0~37位置的空间,根据 原则3,它所占总空间应该为 其内部最大成员大小的整数倍MyStruct3的最大成员大小为 8,所以,其占用内存空间为 0 ~ 39,共 40字节空间。其内存分布如下图所示:

内存对齐3.png

内存优化(属性重排)

在我们讲解第一个示例的时候,我们可以看出,结构体内存的大小和成员变量的大小和其排放顺序有关,两个结构体如果拥有同样的属性,但其属性排放顺序不一致,会导致占用内存的大小不一致。原因如下:

@interface LYPerson : NSObject

@property(nonatomic, copy) NSString *name;
@property(nonatomic, assign) char a;
@property(nonatomic, assign) int c;
@property(nonatomic, assign) short d;
@end

@implementation LYPerson

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        LYPerson *person = [LYPerson alloc];
        person.c  = 5;
        person.a = 'a';
        person.name = @"LY";
        person.d = 2;
        NSLog(@"%ld", class_getInstanceSize(person.class));

    }
    return 0;
}

首先,我们来看下输出结果:

2020-09-12 13:24:17.099525+0800 KCObjc[59477:1943607] 24

为什么是24 ???

我们可以通过lldb指令查看一下内存分布情况

(lldb) po person                              \\  1
<LYPerson: 0x1012492c0>
(lldb) memory read/8gx 0x1012492c0 \\ 2
0x1012492c0: 0x001d80010000238d 0x0000000500020061
0x1012492d0: 0x0000000100001010 0x0000000000000000
0x1012492e0: 0x0000000000000000 0xbd2293c8794d4e12
0x1012492f0: 0x00000001003f4000 0x0000000000000001

(lldb) x/8gx 0x1012492c0            \\ 3
0x1012492c0: 0x001d80010000238d 0x0000000500020061
0x1012492d0: 0x0000000100001010 0x0000000000000000
0x1012492e0: 0x0000000000000000 0xbd2293c8794d4e12
0x1012492f0: 0x00000001003f4000 0x0000000000000001
(lldb) po 0x001d80010000238d & 0x00007ffffffffff8ULL // 1
LYPerson 

(lldb) po 0x0000000100001010 // 2
LY

(lldb) po 0x0005 //3
5

(lldb) po 0x0002 // 4
2

(lldb) po 0x0061 //5 
97

其内存分布如下所示:


LYPerson内存分布.png

总结:

我们在这里首先讨论了,内存对齐的三原则单个结构体的内存分布结构体嵌套的内存分布,以及 iOS中的内存对象的属性重排和其内存分布

上一篇 下一篇

猜你喜欢

热点阅读