美文网首页
OC实例对象占据空间大小

OC实例对象占据空间大小

作者: 川少叶 | 来源:发表于2018-10-27 20:46 被阅读22次

    OC中的类是基于C/C++的结构体实现的,通过如下命令可以将OC代码转换成C/C++代码

    xcrun  -sdk  iphoneos  clang  -arch  arm64  -rewrite-objc  OC源文件  -o  输出的CPP文件
    

    从最简单的NSObject入手,使用以上命令转换如下的OC代码:

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            NSObject *object = [[NSObject alloc] init];
        }
        return 0;
    }
    

    在转换的cpp代码中,找到NSObject的结构体定义

    typedef struct objc_class *Class;
     struct NSObject_IMPL {
        Class isa;
     };
    

    对比OC中NSObject的定义

    @interface NSObject <NSObject> {
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wobjc-interface-ivars"
        Class isa  OBJC_ISA_AVAILABILITY;
    #pragma clang diagnostic pop
    }
    @end
    

    根据NSObject的结构体定义,一个NSObject只包含一个Class指针,在64位机器上,占据的空间大小应该是8个字节,其实质是成员变量占据的空间大小

    那NSObject实例对象占据的空间是多少,请看下面的代码。答案是16。

    void theSizeOfNSObject() {
        NSObject *object = [[NSObject alloc] init];
        
        // 根据objc源码,class_getInstanceSize表示成员变量占据的空间大小。
        NSLog(@"NSObject class_getInstanceSize: %zd", class_getInstanceSize([NSObject class]));
        // 根据objc源码,malloc_size表示该实例对象占据的空间大小,最小是16
        NSLog(@"NSObject alloc size: %zd", malloc_size((__bridge const void *)object));
    }
    

    查看Objc runtime的源码,找到class_getInstanceSizeallocWithZone的实现。

    • class_getInstanceSize实质是实例变量占据的空间大小,并且会进行字节对齐
    • allocWithZone中使用instanceSize分配空间大小,空间大小至少是实例变量占据的空间,如果小于16字节,则还是会分配16字节
    size_t class_getInstanceSize(Class cls)
    {
        if (!cls) return 0;
        return cls->alignedInstanceSize();
    }
    
    // Class's ivar size rounded up to a pointer-size boundary.
    // 注意会字节对齐
    uint32_t alignedInstanceSize() {
        return word_align(unalignedInstanceSize());
    }
    
    // allocWithZone方法,会调用该方法
    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;
    }
    

    定义两个稍复杂的类。其中需要注意的是,Student中属性score,被转换成结构体中_scroe

    @interface Person : NSObject {
        @public
        int _age;
    }
    @end
    
    @interface Student : Person {
        @public
        int _num;
    }
    @property (nonatomic, assign) int score;
    
    @end
    

    通过以上命令生成cpp文件,Person和Student的结构体如下:

    // Person转换成的结构体
    struct Person_IMPL {
        struct NSObject_IMPL NSObject_IVARS;
        int _age;
    };
    
    // Student转换成的结构体
    struct Student_IMPL {
        struct Person_IMPL Person_IVARS;
        int _num;
        int _score;
    };
    

    那Person和Student对象占据空间是多大?实际需要考虑以下两个因素:

    • 结构体中成员变量的字节对齐
    • 苹果分配空间的原则,字节数是16的倍数,见libmalloc源码
    void theSizeOfPerson() {
        Person *person = [[Person alloc] init];
        person->_age = 16;
        
        // Person的成员变量累加占据的空间是12,因为结构体字节对齐,实际是16个字节
        NSLog(@"Person class_getInstanceSize: %zd", class_getInstanceSize([Person class]));
        
        // 实例对象占据的空间大小,16个字节
        NSLog(@"Person alloc size: %zd", malloc_size((__bridge const void *)person));
    }
    
    void theSizeOfStudent() {
        Student *stu = [[Student alloc] init];
        stu->_num = 4;
        
        // Student的成员变量累加占据的空间是20,因为结构体字节对齐,实际是24
        NSLog(@"Student class_getInstanceSize: %zd", class_getInstanceSize([Student class]));
        
        // 根据libmalloc源码,分配给对象的空间,是16的倍数,32个字节
        NSLog(@"Student alloc size: %zd", malloc_size((__bridge const void *)stu));
    }
    

    OC对象和结构体可以进行转化。

    void instanceToStruct() {
        Person *person = [[Person alloc] init];
        person->_age = 4;
    
        struct Person_IMPL *personImpl = (__bridge struct Person_IMPL *)person;
        NSLog(@"person instance age is %d,struct personImpl age is %d", person->_age, personImpl->_age);
    }
    

    参考

    苹果源码列表:https://opensource.apple.com/tarballs/
    Demo地址:https://github.com/xiaoLong1010/DeepObjectiveC/tree/master/01-ObjectSize

    相关文章

      网友评论

          本文标题:OC实例对象占据空间大小

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