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 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 {
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;
}