OC 对象的本质02

2018-08-27  本文已影响0人  SKY_Tang

自定义类的内存本质

自定义一个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对象 两个对象的内存结构示意图
上一篇下一篇

猜你喜欢

热点阅读