一个NSObject对象占多大内存
先说结论
一个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.
这里的People_IMPL是什么东西呢?
先说结论,这是用来初始化class_ro_t的,因为我在c++的文件里搜索,只出现了俩次,一次是在定义(上面的图片),另外一次就是在class_ro_t的初始化函数里
可以看到,结构体用在了计算instanceSize的地方。
那是不是说,对象的大小就是这个结构体的大小呢?我们来打印一下对象。
是不是和刚刚的_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的倍数。
当然这里的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个字节。
如果是属性,属性其实就是set/get方法+成员变量。而方法不占对象的空间。
结论
如果没有成员变量/属性,一个继承于NSObject对象和NSObject对象的大小是一样的,都是16个字节,其中8个字节是isa指针。在运行期初始化。