欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

一个NSObject对象占多大内存

程序员文章站 2022-04-13 11:29:21
...

先说结论

一个NSObject对象占16个字节。

探究原理

之前runtime系列的文章中写过,编译期会将objc_class结构体中的class_ro_t结构体初始化,那篇文章没有讲是如何初始化的,学完了分类后,在转为c++的代码里我看到了一些眉目。
首先这是main.m文件

#import <Foundation/Foundation.h>
#import "Father.h"

@interface Student : NSObject {
    int _age;
}

@end

@implementation Student
@end

@interface People : Student {
    int _number;
}

@end

@implementation People
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Student *student = [[Student alloc] init];
        People *people = [[People alloc] init];
        NSLog(@"123");
    }
    return 0;
}

然后我们定义的类呢有俩种形式,一种是之前文章里写的objc_class,类是在runtime期间被初始化的,所以现在的类结构体还都只是objc_object.
一个NSObject对象占多大内存
这里的People_IMPL是什么东西呢?
先说结论,这是用来初始化class_ro_t的,因为我在c++的文件里搜索,只出现了俩次,一次是在定义(上面的图片),另外一次就是在class_ro_t的初始化函数里
一个NSObject对象占多大内存
一个NSObject对象占多大内存
可以看到,结构体用在了计算instanceSize的地方。
那是不是说,对象的大小就是这个结构体的大小呢?我们来打印一下对象。
一个NSObject对象占多大内存
是不是和刚刚的_IMPL结构体很相似,我们再来打印大小

俩个函数

NSLog(@"objc对象实际需要的内存大小: %zd", class_getInstanceSize([objc class]));
        NSLog(@"objc对象实际分配的内存大小: %zd", malloc_size((__bridge const void *)(objc)));

这个class_getInstanceSize的最终调用

// Class's ivar size rounded up to a pointer-size boundary.
 uint32_t alignedInstanceSize() const {
        return word_align(unalignedInstanceSize());
    }

这个函数返回的是成员变量的大小,也就是_IMPL结构体的大小。
而malloc_size返回的是对象的实际的内存大小,也就是堆空间里分配给这个对象的内存大小
提前说明一下,堆空间的大小也是对齐的,是16的倍数。
一个NSObject对象占多大内存
当然这里的16其实是另外一个原因,原来的博客也讲过,alloc的时候

size_t instanceSize(size_t extraBytes) const {
        if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
            return cache.fastInstanceSize(extraBytes);
        }

        size_t size = alignedInstanceSize() + extraBytes;
        // CF requires all objects be at least 16 bytes.
        if (size < 16) size = 16;
        return size;
    }

最少是16,如果超过了16,返回的值和调用getinstanceSIze返回的是一致的,这里计算好后需要调用calloc全部初始化0,而calloc会进行内存对齐,对齐为16的倍数,所以malloc_size返回16的倍数是正确的值。

@interface Student : NSObject {
    int _age;
}

@end

@implementation Student
@end

@interface People : Student {
    int _number;
    int _extr;
}

@end

isa指针占了8个字节,三个成员变量占了12,一共20个字节,按照结构体内存对齐后是24字节,再按照内存对齐后是32个字节。
一个NSObject对象占多大内存
如果是属性,属性其实就是set/get方法+成员变量。而方法不占对象的空间。

结论

如果没有成员变量/属性,一个继承于NSObject对象和NSObject对象的大小是一样的,都是16个字节,其中8个字节是isa指针。在运行期初始化。