一个NSObject对象占用多少内存?
一开始想到的方法可以直接用sizeof打印,我们直接用这个打印看一下NSObject对象大小.
NSObject *obj = [[NSObject alloc] init];
NSLog(@"%zd",sizeof(obj));
sizeofNSObject
从打印来看,这个对象大小8字节.
所以对象大小就是8字节??我们来研究一下...
OC底层实现
OC是基于C/C++实现的,意味着编译是这个过程OC-->C/C++-->汇编--->机器码.
OC编译过程
其实OC能实现面向对象跟C++分不开,是基于C++的结构体实现.C++的结构体跟Class几乎是一样的.
1.OC利用Xcode编译成C++
$ xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 输出的CPP文件
2.OC对象的本质
1.将代码编译成C++
$ xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
可以看到一个文件main-arm64.cpp,大概3万多行的代码.最终main函数转成的几行代码在最下方,也可以看到objc_msgsend的消息机制:
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
NSObject *obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_h7_n1ts5dlj4hgg5sky9q8w7c7w0000gp_T_main_684d68_mi_0,sizeof(obj));
return 0;
}
}
在文件中可以到一个结构体NSObject_IMPL 基本就是NSObject实现,类似于下图,你定义一个interface,在底层就是一个结构体
NSObject底层结构体
可以看到NSObject对象的底层就只有一个isa指针,我们知道64位指针大小就是8字节.从这里看对象也是8字节.但是还有另外方式打印对象大小,OC的方法,我们试试:
#import <Foundation/Foundation.h>
#import <malloc/malloc.h>
#import <objc/runtime.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSObject *obj = [[NSObject alloc] init];
NSLog(@"%zd",malloc_size((__bridge const void *)(obj)));
NSLog(@"%zd",class_getInstanceSize([NSObject class]));
NSLog(@"%zd",sizeof(obj));
return 0;
}
}
运行结果:
发现分配了16个字节,但是对象大小只占了8字节?
源码查看NSObject对象分配
查看objc的源码
可看到alloc的底层做了内存对齐,最少为16字节.
总结:
1.系统分配了16个字节给NSObject对象(通过malloc_size函数获得)
2.但NSObject对象内部只使用了8个字节的空间(64bit环境下,可以通过class_getInstanceSize函数获得)
网友评论