美文网首页
OC 对象的本质02

OC 对象的本质02

作者: SKY_Tang | 来源:发表于2018-08-27 18:35 被阅读0次

    自定义类的内存本质

    自定义一个student 类

    @interface Student : NSObject {
        @public
        int _age;
        int _height;
    }
    @end
    
    @implementation Student
    
    @end
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            Student *stu = [[Student alloc] init];
            stu->_age = 7;
            stu->_height = 15;
        }
        return 0;
    }
    

    将Objective-c代码转换成 C\C++的代码

    xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
    

    找到Student 的 C++实现

    struct Student_IMPL {
        struct NSObject_IMPL NSObject_IVARS;
        int _no;
        int _age;
    };
    

    NSObject_IMPL的 C++实现

    struct NSObject_IMPL {
        Class isa;
    };
    

    Class 的C++实现

    typedef struct objc_class *Class;
    

    由于NSObject_IMPL结构体只有一个class类型的 isa 成员,Student_IMPL可以简化成

    struct Student_IMPL {
        Class isa;
        int _no;
        int _age;
    };
    
    Student_IMPL内存结构

    假设 isa的地址是0x100400110,class 是指向结构体的指针,内存大小8个字节,int 在64bit 内存大小是4个字节,所以初步得出
    初步结论:Student的对象占用内存大小16个字节
    现在用class_getInstanceSizemalloc_size两个方法来打印下返回大小

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            Student *stu = [[Student alloc] init];
            stu->_no = 4;
            stu->_age = 5;
            
            NSLog(@"%zd", class_getInstanceSize([Student class]));
            
            NSLog(@"%zd", malloc_size((__bridge const void *)stu));
        }
        return 0;
    }
    
    打印结果

    打印结果都是16,与结论相同。

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            Student *stu = [[Student alloc] init];
            stu->_no = 4;
            stu->_age = 5;
            
    //        NSLog(@"%zd", class_getInstanceSize([Student class]));
    //        
    //        NSLog(@"%zd", malloc_size((__bridge const void *)stu));
            
            
            struct Student_IMPL *studentImpl = (__bridge struct Student_IMPL *)stu;
            NSLog(@"no---%d; age-----%d", studentImpl->_no, studentImpl->_age);
        }
        return 0;
    }
    
    打印结果

    我们把Student类的对象stu强制转换成Student_IMPL结构体类型studentImpl,打印studentImpl结构体的成员_no_age,打印结果也正好是4和5,这也侧面验证了Student类的 C++实现就是Student_IMPL结构体类型。

    现在我们用View Memory工具来查看下stu的内存情况

    stu内存地址
    内存情况

    可以看到0x100417c08是04,0x100417c0c是05,也就是_no和_age 的值。

    修改_no 的值

    修改0x100417c08为8,stu_no的值也变成了8

    自定义一个person 类和一个继承 person 类的 student 类

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

    将Objective-c代码转换成 C\C++的代码

    xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
    

    找到相应的 C\C++的代码得实现

    struct NSObject_IMPL {
        Class isa;
    };
    
    struct Person_IMPL {
        struct NSObject_IMPL NSObject_IVARS;
        int _age;
    };
    
    struct Student_IMPL {
        struct Person_IMPL Person_IVARS;
        int _no;
    };
    

    大致猜测Person类的对象占用16个字节实际只用了12个字节。我们来打印验证一下

    Person对象

    看到class_getInstanceSize方法打印结果有差异,具体来看看class_getInstanceSize的源代码

    class_getInstanceSize
    alignedInstanceSize
    看到word_align()方法,意思就是要按字节对齐。

    内存对齐:结构体的大小必须是最大成员大小的倍数

    再来看Person类的 C++实现,最大成员变量isa是8个字节,所以大于12的最小倍数就是16,也就是class_getInstanceSize返回16。

    大致猜测Student类的对象占用16个字节实际使用了16个字节。我们来打印验证一下

    student对象 两个对象的内存结构示意图

    相关文章

      网友评论

          本文标题:OC 对象的本质02

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