OC对象的本质

300 阅读2分钟

NSObject的本质

  • 我们平时编写的OC代码,底层实现是C/C++代码 OC ---> C/C++ ---> 汇编语言 ---> 机器语言
  • OC的面向对象都是基于C/C++的结构体实现的
  • 将OC代码转换为C/C++代码
    clang -rewrite-objc main.m -o main.cpp
    
    先通过Xcode指定是iPhoneos,然后编译器指定arm64架构,重写objc文件,输出到cpp文件里
    xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
    
    如果需要链接其他库,使用-framework参数,比如-framework UIKit
  • NSObject在内存里面的布局
typedef struct objc_class *Class;
struct NSObject_IMPL {
  Class isa;
}
@interface NSObject{
  Class isa;
}
  • 一个NSObject对象占用多少内存?系统分配了16个字节给NSObject对象(通过malloc_size函数获得),但NSObject对象内部只使用了8个字节的空间(64bit环境下,可以通过class_getInsatnceSize函数)
 NSObject *obj = [[NSObject alloc] init]; 
 //获取NSObject实例对象的成员变量所占用的大小:8
 NSLog(@"%zd",class_getInstanceSize([NSObject class]));
 //获得obj指针所指向内存的大小:16
 NSLog(@"%zd",malloc_size((__bridge const void *)(obj)));

Student的本质

struct NSObject_IMPL {
    Class isa; //8
};

//底层转换
struct Student_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    int _no;//4
    int _age;//4
};

@interface Student : NSObject
{
    @public
    int _no;
    int _age;
}
@end

@implementation Student

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Student *student = [[Student alloc] init];
        //16
        NSLog(@"%zd",malloc_size((__bridge const void *)(student)));
        //16
        NSLog(@"%zd",class_getInstanceSize([Student class]));
    }
    return 0;
}

更复杂的继承结构

struct NSObject_IMPL {
    Class isa;
};

struct People_IMPL {
    struct NSObject_IMPL NSObject_IVARS;//8
    int _age;//4
};//16, 1:OC对象的占用内存至少16个字节 2:内存对齐:结构体的最终大小必须是最大成员大小的倍数 8 * 2 = 16

struct Student_IMPL {
    struct People_IMPL People_IVARS;//16
    int _no;//4
};//16

@interface People : NSObject
{
    int _age;
}
@end

@implementation People

@end

@interface Student : People
{
    @public
    int _no;
}
@end

@implementation Student

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
    //class_getInstanceSize:返回的是实例对象至少需要多少内存空间  mallocSize:返回系统实际分配内存的大小
        People *people = [[People alloc] init];
        NSLog(@"people *** mallocSize === %zd, instanceSize === %zd",malloc_size((__bridge const void *)(people)),class_getInstanceSize([People  class])); // 16  16
        Student *student = [[Student alloc] init];
        NSLog(@"student *** mallocSize === %zd, instanceSize === %zd",malloc_size((__bridge const void *)(student)),class_getInstanceSize([Student  class])); // 16  16
    }
    return 0;
}

alloc的size分析

struct NSObject_IMPL {
    Class isa; //8
};

struct Person_IMPL {
    struct NSObject_IMPL NSObject_IVARS; //8
    int _age; //4
    int _height; //4
    int _no; //4
};//计算结构体大小,内存对齐原则:最终大小必须是结构体内最大成员大小的倍数,8 * 3 = 24

@interface Person: NSObject
{
    int _age;
    int _height;
    int _no;
}
@end

@implementation Person
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *person = [[Person alloc] init];
        //32 24 为啥mallocSize是32?根据层层源码研究,alloc->allocWitnZone->发现是calloc调用导致的->malloc_zone_calloc->结论:操作系统分配内存也有对齐的概念,Buckets sized {16, 32, 48, ..., 256},一般是16的倍数,所以24变为16的倍数,就是32了
        NSLog(@"mallocSize = %zd, instanceSize = %zd",malloc_size((__bridge const void *)(person)),class_getInstanceSize([Person class]));
    }
    return 0;
}