Apple OSS Distributions · GitHub
Apple Open Source 开源源码链接
面试题1
一个NSObject对象占用多少内存?
系统分配了16个字节给NSObject对象(通过malloc_size函数获得)
但NSObject对象内部只使用了8个字节的空间(64bit环境下,可以通过class_getInstanceSize函数获得)
1)OC中的对象、类主要是基于C\C++的结构体来实现的.C\C++的结构体支撑了我们的面向对象。
Class: 是一个指针 占8个字节。
NSObject *obj = [NSObject alloc ] init];
[NSObject alloc ] init] 就是 分配存储空间给结构体
分配完以后,还有一个指针*,利用这个指针要指向这个对象,就要把对象的内存地址赋值给这个指针。指针存储内存地址,才能找到那个对象。所以这个isa指针的地址,就是结构体在内存中的地址。
isa指针占用了8个字节,但是在alignedInstanceSize里面,小于16会强制使用16个字节。所以分配了16个字节。
如果没有强制16字节,也会有内存对齐规定。内存对齐:为了 提高CPU的访问速度,会进行内存对齐操作。结构体的最终大小必须是最大成员大小的倍数。
结构体内存对齐:计算结构体大小的时候 ,内存对齐
操作系统内存对齐:苹果操作系统给分配内存的时候,也存在内存对齐的概念
2) 2个容易混淆的函数
class_getInstanceSize:成员变量占用的大小(对齐过的)
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());}// May be unaligned depending on class's ivars.uint32_t unalignedInstanceSize() {assert(isRealized());return data()->ro->instanceSize;}size_t instanceSize(size_t extraBytes) {size_t size = alignedInstanceSize() + extraBytes;// CF requires all objects be at least 16 bytes.if (size < 16) size = 16;return size;}
ps:
NSLog(@"%zd", class_getInstanceSize([Student class])); ---->24
NSLog(@"%zd", malloc_size((__bridge const void *)stu)); ----->32
class_getInstanceSize
操作系统,堆空间里面,都是16的倍数。
传递24个字节给calloc,内存对齐后 分配的内存快大小是--->NANO_MAX_SIZE
#define NANO_MAX_SIZE 256 /* Buckets sized {16, 32, 48, 64, 80, 96, 112, ...} */
id
class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone)
{return _class_createInstanceFromZone(cls, extraBytes, zone);
}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 performancebool 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 {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;
}