带你深入理解iOS-内存对齐

2020-02-23  本文已影响0人  002and001

前言

源码地址

MemoryAlignment

简介

内存对齐”应该是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。如果你想了解更加底层的秘密,探究“内存对齐”对你就不应该再模糊了。

特别对于我们学习底层源码,是需要掌握的知识点之一,下面我就结合百度百科-内存对齐以及实际的demo进行详细分析。

1、规则定义

2、规则解析

3、实例分析

demo例子中我们定义具有相同类型和个数成员的结构体,但是其定义的顺序不同成员不同,并对其进行赋值,然后结合规则,详细进行分析。

基础知识点介绍

1.一个字节包含8个二进制位
2.一个十六进制位可用4个二进制位表示
3.一个字节可以由2个十六进制位表示
0x0000 0000 0000 0008表示16个16进制位,可以表示8个字节
所以8可以用8个字节0x0000 0000 0000 0008表示,或者4个字节0x0000 0008,或者2个字节0x0008,取决于定义8的数据类型。
字符'a'换成ASCII码为97,可以用 0x61表示。
此外,iOS系统的编译平台是按照小端法进行编译。

下面进入具体的实例分析,
环境:
Xcode 11.3.1,Deployment Target:10.15
代码如下:
CommandLineTool类型工程的main.m文件中


#import <Foundation/Foundation.h>

struct Person1 {
    char a;
    long b;
    int c;
    short d;
}MyPerson1;

struct Person2 {
    long b;
    char a;
    int c;
    short d;
}MyPerson2;

struct Person3 {
    long b;
    int c;
    char a;
    short d;
}MyPerson3;

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        MyPerson1.a = 'a';
        MyPerson1.b = 8;
        MyPerson1.c = 4;
        MyPerson1.d = 2;
        
        MyPerson2.b = 18;
        MyPerson2.a = 'a';
        MyPerson2.c = 14;
        MyPerson2.d = 12;
        
        MyPerson3.b = 28;
        MyPerson3.c = 24;
        MyPerson3.a = 'a';
        MyPerson3.d = 22;
        NSLog(@"Adress=======MyPerson1:%p,MyPerson2:%p,MyPerson3:%p",&MyPerson1,&MyPerson2,&MyPerson3);  
        NSLog(@"Size=======MyPerson1:%lu,MyPerson2:%lu,MyPerson3:%lu",sizeof(MyPerson1),sizeof(MyPerson2),sizeof(MyPerson3));

    }
    return 0;
}

分析MyPerson1

struct Person1 {
    char a;
    long b;
    int c;
    short d;
}MyPerson1;

分析MyPerson2

struct Person2 {
    long b;
    char a;
    int c;
    short d;
}MyPerson2;

分析MyPerson3

struct Person3 {
    long b;
    int c;
    char a;
    short d;
}MyPerson3;

验证

如图输出结构体成员信息


lldb输出.png

优化lldb的打印输出如下

优化输出

OC对象分析

仿照上面的3个结构体定义3个类Teacher1,Teacher2,Teacher3

@interface Teacher1 : NSObject

@property (nonatomic, assign) char a;
@property (nonatomic, assign) long b;
@property (nonatomic, assign) int c;
@property (nonatomic, assign) short d;

@end
@interface Teacher2 : NSObject

@property (nonatomic, assign) long b;
@property (nonatomic, assign) char a;
@property (nonatomic, assign) int c;
@property (nonatomic, assign) short d;

@end
@interface Teacher3 : NSObject

@property (nonatomic, assign) int c;
@property (nonatomic, assign) long b;
@property (nonatomic, assign) char a;
@property (nonatomic, assign) short d;

@end

main.m中添加如下代码

        Teacher1 *t1 = [[Teacher1 alloc] init];
        t1.a = 'a';
        t1.b = 8;
        t1.c = 4;
        t1.d = 2;
        
        Teacher2 *t2 = [[Teacher2 alloc] init];
        t2.b = 18;
        t2.a = 'b';
        t2.c = 14;
        t2.d = 12;
        
        Teacher3 *t3 = [[Teacher3 alloc] init];
        t3.b = 28;
        t3.c = 24;
        t3.a = 'c';
        t3.d = 22;
对象的输出如下
image.png
@interface Teacher1 : NSObject

@property (nonatomic, assign) double height;

@end

Teacher1 *t1 = [[Teacher1 alloc] init];
t1.height = 175;

由于float和double的位表示是经过一定算法得到,无法直接通过简单手工计算得出,可以使用lldb命令:p/x (double)175得到的其位表示,再与x/4gx t1中的进行对比。

4、思考

下面代码输出什么?

NSLog(@"sizeof=======t1:%lu,t2:%lu,t3:%lu",sizeof(t1),sizeof(t2),sizeof(t3));
NSLog(@"class_getInstanceSize=======t1:%lu,t2:%lu,t3:%lu",class_getInstanceSize(t1.class),class_getInstanceSize(t2.class),class_getInstanceSize(t3.class));
NSLog(@"malloc_size=======t1:%lu,t2:%lu,t3:%lu",malloc_size((__bridge const void*)t1),malloc_size((__bridge const void*)t2),malloc_size((__bridge const void*)t3));

输出如下:

sizeof=======t1:8,t2:8,t3:8
class_getInstanceSize=======t1:24,t2:24,t3:24
malloc_size=======t1:32,t2:32,t3:32

关于class_getInstanceSizemalloc_size的详解参考《OC底层系列二》-对象中的class_getInstanceSize以及malloc_size部分。

总结

上一篇 下一篇

猜你喜欢

热点阅读