注:文章为自己学习李明杰老师的OC底层视频做的随手笔记
我们平时编写的Objective-C的代码,底层实现都是C/C++来实现的,所以Objective-C的面向对象都是基于C/C++的数据结构来实现的,具体是基于什么来实现的呢?
NSObject的声明文件可以看到是一个Class的isa属性
@interface NSObject {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
Class isa OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
然后编译成C++的代码会发现是一个结构体
struct NSObject_IMPL {
Class isa;
};
那么一个NSObject对象占用多少内存呢?
实际上NSObject对象里面只有一个isa指针,指向一个结构体
typedef struct objc_class *Class;
一个指针占用8个字节,是不是这个NSObject对象就在内存中占用8个字节呢
通过malloc的方法获取创建的NSObject的对象指针所指向的内存的大小
NSObject *obj = [[NSObject alloc] init];
NSLog(@"%zd",malloc_size((__bridge const void *)obj));
2019-12-04 20:48:49.819768+0800 test1[29620:292876] 16
答案是16个字节
但是对象里面就一个isa指针,应该是占用8个字节才是对的,同样,用runtime方法验证了,对象的成员变量占用了8个字节,就是这个指针的大小
NSObject *obj = [[NSObject alloc] init];
//对象的成员变量占用的大小,j就是这个对象至少需要多大内存
NSLog(@"%zd",class_getInstanceSize([NSObject class]));
2019-12-04 20:44:25.296641+0800 test1[29566:289914] 8
那为什么给obj对象分配了16个字节呢,实际上查看OC的源码会发现,alloc给对象分配空间的时候,AllocWithZone
的实现就明白了了
到这里就很明了了,所以一个OC对象至少占用16个字节,实际上alignedInstanceSize()返回的是8个字节,小于16,默认返回最小16
如果创建一个student的对象,他的本质又是什么呢,
带有一个age属性的student对象
@interface students : NSObject{
int _age;
}
编译成C++可以看到
struct students_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _age;
};
还是一个结构体,student继承NSObject,第一个就是NSObject的isa指针,父类的成员变量放到前面,自己的放到最后,那么student占用多少个字节,age占用4个字节,isa占用8个,应该是12个,但是运行发现,其实是占用16个,原因是内存对齐的规则:结构体的最终大小必须是最大成员的倍数,isa占用8个字节,所以增加了一个age属性,就占用8*2=16字节,而不是8+4=12字节了
students *stu = [[students alloc] init];
//对象的成员变量占用的大小,j就是这个对象至少需要多大内存
NSLog(@"%zd",class_getInstanceSize([students class]));
//分配给对象的大小
NSLog(@"%zd",malloc_size((__bridge const void *)stu));
2019-12-04 21:21:45.602333+0800 test1[29811:309407] 16
2019-12-04 21:21:45.602937+0800 test1[29811:309407] 16
继续给student增加属性得到验证,两个属性同样还是占用16个字节,说明一个属性时分配的16个字节有4个是空的
继续给对象增加3属性,发现
对象占用24个字节,为什么不是分配24个字节而是32个呢,根据内存对齐,结构体最大的是8,分配24个没问题呀,看明杰老师读源码发现,OC对象的最小大小是16字节,其实也是根据内存对齐,OC创建的对象永远都是16的倍数
总结
一个NSObject对象占用多少个内存?
系统分配了16个字节给NSObject对象,(可以通过malloc_size函数获得)
但是NSObject对象内部只使用了8个字节的空间(64位环境下,可以通过class_getInstanceSize函数获得)