本篇文章主要介绍了" NSObject 底层本质",主要涉及到方面的内容,对于IOS开发感兴趣的同学可以参考一下:
一、OC 转 C/C++二、NSObject 对象内存布局三、NSObject 内存大小四、OC 对象内存布局五、OC 对象内存大小一、OC 转 C/C++OC...
//#import NSObject *obj = [[NSObject alloc] init];
// 获得NSObject实例对象的成员变量所占用的大小 >> 8
NSLog(@"%zd", class_getInstanceSize([NSObject class]));
// 获得obj指针所指向内存的大小 >> 16
NSLog(@"%zd", malloc_size((__bridge const void *)obj));
class_getInstanceSize方法可以获取实例对象的成员变量大小,即创建一个实例对象,至少需要多少内存。malloc_size方法可以获取对象指针所指向内存大小,即创建一个实例对象,实际上分配了多少内存。两个方法的区别具体可以看runtime底层源码观察其区别。OC 底层源码一般可在该网站查看。
3.2 class_getInstanceSize 函数
class_getInstanceSize底层实现如下,其中英文注释很清晰的描述了该方法返回的是成员变量(Class's ivar)大小。
size_t class_getInstanceSize(Class cls)
{
if (!cls) return 0;
return cls->alignedInstanceSize();
}
// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
3.3 alloc 函数
OC 中的alloc在底层调用 runtime 的allocWithZone方法:
id
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone)
{
id obj;
#if __OBJC2__
// allocWithZone under __OBJC2__ ignores the zone parameter
(void)zone;
obj = class_createInstance(cls, 0);
#else
if (!zone) {
obj = class_createInstance(cls, 0);
}
else {
obj = class_createInstanceFromZone(cls, 0, zone);
}
#endif
if (slowpath(!obj)) obj = callBadAllocHandler(cls);
return obj;
}
id
class_createInstance(Class cls, size_t extraBytes)
{
return _class_createInstanceFromZone(cls, extraBytes, nil);
}
static __attribute__((always_inline))
id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
bool cxxConstruct = true,
size_t *outAllocatedSize = nil)
{
if (!cls) return nil;
assert(cls->isRealized());
// Read class's info bits all at once for performance
bool hasCxxCtor = cls->hasCxxCtor();
bool hasCxxDtor = cls->hasCxxDtor();
bool fast = cls->canAllocNonpointer();
size_t size = cls->instanceSize(extraBytes);
if (outAllocatedSize) *outAllocatedSize = size;
id obj;
if (!zone && fast) {
obj = (id)calloc(1, size);
if (!obj) return nil;
obj->initInstanceIsa(cls, hasCxxDtor);
}
else {
if (zone) {
obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
} else {
//该处调用了C语言的 calloc 函数开辟空间,所以查看NSObject 对象的创建开辟空间大小应当依次为切入点,查看size 参数来源
obj = (id)calloc(1, size);
}
if (!obj) return nil;
// Use raw pointer isa on the assumption that they might be
// doing something weird with the zone or RR.
obj->initIsa(cls);
}
if (cxxConstruct && hasCxxCtor) {
obj = _objc_constructOrFree(obj, cls);
}
return obj;
}
上述代码调用了C语言的 calloc函数开辟空间,所以查看NSObject 对象的创建开辟空间大小应当依次为切入点,查看size参数来源。alignedInstanceSize()方法是 class_getInstanceSize 方法底层来源,所以下面代码中的extraBytes变量值实际为 0。非常值得注意的是,下述代码中明确指出CF requires all objects be at least 16 bytes.,即 CF 对象至少为 16 位大小。