美文网首页
OC底层原理学习笔记(一) - OC对象的本质

OC底层原理学习笔记(一) - OC对象的本质

作者: hyq1101 | 来源:发表于2022-02-26 22:29 被阅读0次

    一、OC的本质

    我们平时编写的Objective-C代码,底层实现其实都是C\C++代码
    所以Objective-C的面向对象都是基于C\C++的数据结构实现的
    Objective-C的对象、类主要是基于C\C++的结构体实现的

    如何将Objective-C代码转换为C\C++代码?
    在终端输入:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 输出的cpp文件
    例如:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp

    二、一个NSObject对象占用多少内存?

    系统分配了16个字节给NSObject对象(通过malloc_size函数获得系统实际分配的内存大小)
    但NSObject对象内部只使用了8个字节的空间(64位环境下,可以通过class_getInstanceSize函数获得)

    NSObject *obj = [[NSObject alloc] init];
    // 获得NSObject实例对象的成员变量所占用的大小:8
    NSLog(@"%zd", class_getInstanceSize([NSObject class]));
    // 获得obj指针所指向内存的大小:16
    NSLog(@"%zd", malloc_Size((__bridge const void *)obj));
    
    // C++代码,内部只有一个成员变量isa指针,所以只占用8字节
    struct NSObject_IMPL {
        Class isa;
    };
    
    // runtime底层源码,size最小为16
    size_t instanceSize(size_t extraBytes) {
        size_t size = alignedInstanceSize() + extraBytes;
        // CF requires all objects be at least 16 bytes.
       if (size < 16) size = 16;
       return size;
    }
    

    三、一个Person对象、一个Student对象占用多少内存空间?

    @interface Person : NSObject {
        int _age;
    }
    
    @interface Student : Person {
        int _no;
    }
    
    // C++代码
    struct NSObject_IMPL {
        Class isa;
    };
    
    struct Person_IMPL {
        struct NSObject_IMPL NSObject_IVARS; // 8
        int _age; // 4
    }; // 16 内存对齐:结构体的大小必须是最大成员大小的倍数
    
    struct Student_IMPL {
        struct Person_IMPL Person_IVARS; // 16,有4个字节是空的正好给_no使用
        int _no; // 4
    }; // 16
    
    // runtime底层源码,size最小为16
    size_t instanceSize(size_t extraBytes) {
        size_t size = alignedInstanceSize() + extraBytes;
        // CF requires all objects be at least 16 bytes.
       if (size < 16) size = 16;
       return size;
    }
    

    1、一个Person对象占用16个字节:isa占用8个字节,_age占用4个字节,8 + 4 < 16,所以取16
    2、一个Student对象占用16个字节:isa占用8个字节,父类的_age占用4个字节,_no占用4个字节,8 + 4 + 4 = 16字节
    3、内存对齐
    计算结构体的大小的内存对齐:结构体的大小必须是最大成员大小的倍数
    系统分配内存的内存对齐方式:16的倍数

    四、OC对象

    OC对象有instance对象(实例对象)、class对象(类对象)、meta-class对象(元类对象),class对象、meta-class对象的本质结构都是struct objc_class

    //instance对象(实例对象)
    NSObject *object1 = [[NSObject alloc] init];
    NSObject *object2 = [[NSObject alloc] init];
    //class对象(类对象)
    //class方法返回的一直是class对象(类对象)
    Class objectClass1 = [object1 class];
    Class objectClass2 = [object2 class];
    Class objectClass3 = object_getClass(object1);
    Class objectClass4 = object_getClass(object2);
    Class objectClass5 = [NSObject class];
    //meta-class对象(元类对象)
    //将类对象当做参数传入,获得元类对象
    Class metaClass = object_getClass(objectClass5);
    NSLog(@"metaClass - %p", metaClass);
    

    1、instance对象(实例对象)

    instance对象就是通过类alloc出来的对象,每次调用alloc都会产生新的instance对象
    instance对象在内存中存储的信息包括:
    (1)isa指针
    (2)其他成员变量

    2、class对象(类对象)

    每个类在内存中有且只有一个class对象
    类对象在内存中存储的信息主要包括:
    (1)isa指针
    (2)superclass指针
    (3)类的属性信息(@property)、类的对象方法信息(instance method)
    (4)类的协议信息(protocol)、类的成员变量信息(ivar)

    3、meta-class对象(元类对象)

    每个类在内存中有且只有一个meta-class对象
    meta-class对象和class对象的内存结构是一样的,但是用途不一样
    在内存中存储的信息主要包括:
    (1)isa指针
    (2)superclass指针
    (3)类的类方法信息(class method)

    五、从源码查看struct objc_class结构

    struct objc_class {
        Class isa;
        Class superclass;
        cache_t cache;             // 方法缓存
        class_data_bits_t bits;    // 用于获取具体的类信息
    };
    
    // bits & FAST_DATA_MASK
    struct class_rw_t {
        uint32_t flags;
        uint32_t version;
        const class_ro_t *ro;
        method_list_t * methods;    // 方法列表
        property_list_t *properties;    // 属性列表
        const protocol_list_t * protocols;  // 协议列表
        Class firstSubclass;
        Class nextSiblingClass;
        char *demangledName;
    };
    
    struct class_ro_t {
        uint32_t flags;
        uint32_t instanceStart;
        uint32_t instanceSize;  // instance对象占用的内存空间
    #ifdef __LP64__
        uint32_t reserved;
    #endif
        const uint8_t * ivarLayout;
        const char * name;  // 类名
        method_list_t * baseMethodList;
        protocol_list_t * baseProtocols;
        const ivar_list_t * ivars;  // 成员变量列表
        const uint8_t * weakIvarLayout;
        property_list_t *baseProperties;
    };
    

    六、对象的isa指针和superclass指针指向哪里?

    image.png

    1、isa指针
    instance对象的isa指针指向class对象
    class对象的isa指针指向meta-class对象
    meta-class对象的isa指针指向基类的meta-class对象
    2、superclass指针
    class对象的superclass指针指向父类的class对象
    如果没有父类,superclass指针为nil
    meta-class对象的superclass指针指向父类的meta-class对象
    基类的meta-class的superclass指针指向基类的class对象

    苹果源码:opensource.apple.com/tarballs
    objc4源码下载:https://opensource.apple.com/tarballs/objc4/

    相关文章

      网友评论

          本文标题:OC底层原理学习笔记(一) - OC对象的本质

          本文链接:https://www.haomeiwen.com/subject/jddcrrtx.html