iOS底层(二)-内存对齐

318 阅读3分钟

一个对象的创建,一般都会伴随着一些属性,但是这些属性是如何排布在对象当中的呢

前提知识

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

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

按照大小相加得知:

MyStruct1 = 1 + 8 + 4 + 2 = 15 MyStruct2 = 8 + 4 + 1 + 2 = 15

打印两个结构体分别做大小:

明显与相加得到结果不一致.因为 计算机为了方便读取内存, 会进行一次内存优化对齐

例如: Struct1中, 向一个8字节内存中存放char a, 剩余7字节. 继续存放double b. 7个字节不够存放,重新开辟一个8字节存放, 剩余0字节. 继续存放c,重新开辟8字节存放c,剩余4字节. 继续存放d, 4字节足够, 剩余2字节; 实际内存为: 1(a) + 7(补充) + 8(b) + 4(c) + 2(d) + 2(补充) = 24 同理计算Struct2: 实际内存为: 8(b) + 4(c) + 1(a) + 2(d) + 1(补充) = 16

实例化的对象与属性

1.首先创建出一个自定义对象,属性如下


@interface MyTest : NSObject
    @property (nonatomic, strong) NSString *name;
    @property (nonatomic, strong) NSString *gender;
    @property (nonatomic, assign) int age;
    
    //@property (nonatomic, assign) char test1;
    //@property (nonatomic, assign) char test2;
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        MyTest *test = [MyTest alloc];
        test.name = @"张三";
        test.age = 20;
        test.gender = @"男";
        
        size_t size = malloc_size((__bridge const void *)test);
        NSLog(@"%@--%zu", test, size);
    }
    return 0;
}

在NSLog处断点,调试程序.

分析:

  1. 首先得到test对象大小为32个字节. 一个初始化出来的对象, 内存中前8个字节一定是isa相关. 那么后面相继为属性 name=8bit gender=8bit age=4bit 共计: isa + name + gender + age = 28 由于alloc底层的机制是开辟内存后会对8字节进行做内存对其运算所以应该是再补齐4字节为32字节

  2. 在控制台打印出test内存

    (由于此对象大小为32, 所以只需要打印出32个字节的数据) 分别打印相关内存数据

第一个为isa不做分析. 第三个第四个可以很明确的知道分别为name与gender 那么第二个就绝对为age 由于age为int类型占据4个字节 所以打印第二片内存是只应该打印4个字节的数据, 即:
后续的00 00 00 00就是alloc底层做的内存对齐所补充的4个字节

  1. 打开test1 test2属性来进行一次验证

初始化属性

    test.test1 = 'A';
    test.test2 = 'B';

重复第二步得到:

通过对比,只有第二部分内存发生了变化 test1与test2分别只占1个字节, 那么再根据小端模式得知, 42 41就应该是test2与test1的值

分别对应A B的ascII值的65 66. 验证正确

附: 大小端模式:

  • 大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。
    
  • 小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。
    
  • 例如: 0x0102(小端) = 0x0201(大端) = 258(iOS中小端模式)