我们平时编写的
Objective-C
代码本质上其实都是通过底层的C\C++
代码的实现的,而C\C++
代码会转变成汇编语言,最终被计算机解释成能识别的机器语言。
正因为OC
底层是通过C\C++
语言实现,故我们可以通过clang
编译器将OC
代码转换成C\C++
语言
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 输出的cpp文件
如果需要链接其他框架,使用-framework
参数。比如-framework UIKit
通过上述转换之后很容易找到 NSObject
类的真正实现
struct NSObject_IMPL {
Class isa;
}
我们发现在NSObject_IMPL
中只有一个名为 isa 的 Class 实例。这个Class
又是一个什么东西呢?
/// An opaque type that represents an
typedef struct objc_class *Class;
发现 Class 实际上是一个指向 objc_class 的结构体指针,其实NSObject
最终是一个指向结构体 objc_class
的名为isa
的结构体指针。
接下来我们通过Runtime
中 的class_getInstanceSize
来查看下NSObject
这个类的实例对象的成员变量的大小
NSObject *obj = [[NSObject alloc] init];
NSLog(@"NSObject实例对象的成员变量所占用的大小为:%zd",class_getInstanceSize([NSObject class]));
通过控制台打印可以发现:
NSObject实例对象的成员变量所占用的大小为:8
综上所述:NSObject
中的成员变量isa
占 8 个字节的大小。
我们也可以通过objc4源码得出此结论:
class_getInstanceSize
在源码中实现如下:
Class's ivar size rounded up to a pointer-size boundary.
一个类的所有成员变量所占用的空间。
那么 OC
中一个 NSObject
对象真的是占8个字节嘛?
接下来我们再通过malloc_size(const void *ptr)
来看下NSObject
这个类所占的内存大小
NSObject *obj = [[NSObject alloc] init];
NSLog(@"obj指针所指向内存大小为:%zd", malloc_size((__bridge const void *)obj));
通过控制台打印可以发现:
obj指针所指向内存大小为:16
为什么这次通过malloc_size(const void *ptr)
打印出来的字节数是16而不是8?。
我们知道在OC
的对象实例中,真正给对象分配内存的方法是:
+ (instancetype)allocWithZone:(struct _NSZone *)zone OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
allocWithZone
在objc4源码又是如何实现的呢?
虽然系统分配了16个字节给NSObject
对象,但是通过class_getInstanceSize
所知NSObject
内部
真正利用的只有8个字节,我们接下来继续研究:
通过Debug->Debug Workflow->View Memory
查看NSObject
对象所分配的内存,如图: