# Objective-C 底层 1. Objective-C 中对象、类主要是基于 C/C++ 中的结构体实现的。 方法一: 可以用 clang 验证。`clang -rewrite-objc main.m -o main.cpp` 转到指定平台代码。`xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp` ``` struct NSObject_IMPL { Class isa; }; /// An opaque type that represents an Objective-C class. typedef struct objc_class *Class; ``` 所以 Class 是指向结构体的指针,所以在 64 位系统中占据8个字节,32位系统占据4个字节。 NSObject 就是结构体占据8个字节。 ![image-20200726130625217](/Users/lbp/Library/Application Support/typora-user-images/image-20200726130625217.png) ![image-20200726125926892](/Users/lbp/Library/Application Support/typora-user-images/image-20200726125926892.png) 发现 `class_getInstanceSize` 和 `malloc_size` 结果不一致。 ```c // Class's ivar size rounded up to a pointer-size boundary. uint32_t alignedInstanceSize() const { return word_align(unalignedInstanceSize()); } ``` `class_getInstanceSize` 返回的是类的实例对象的成员变量的大小(四舍五入等于指针指向对象的大小,所以不精确) ```c extern size_t malloc_size(const void *ptr); /* Returns size of given ptr */ ``` `malloc_size` 返回的就是指针指向的对象大小. ![image-20200726130920234](/Users/lbp/Library/Application Support/typora-user-images/image-20200726130920234.png) 结论: - 当某个类继承自 NSObject 的时候,如果没有其他属性,则这个类占据16个字节。`class_getInstanceSize` 占据 8 , `malloc_size` 占据 16 - 当某个类继承自 NSObject 的时候,如果有其他属性,则这个类占据16个字节。`class_getInstanceSize` 占据 16 , `malloc_size` 占据 16 方法二: 从源代码角度出发验证(从上大下) ```c++ // NSObject.mm // Replaced by ObjectAlloc + (id)allocWithZone:(struct _NSZone *)zone { return _objc_rootAllocWithZone(self, (malloc_zone_t *)zone); } // objc-class-old.mm id _objc_rootAllocWithZone(Class cls, malloc_zone_t *zone) { id obj; if (fastpath(!zone)) { obj = class_createInstance(cls, 0); } else { obj = class_createInstanceFromZone(cls, 0, zone); } if (slowpath(!obj)) obj = _objc_callBadAllocHandler(cls); return obj; } // objc-class-old.mm /*********************************************************************** * _class_createInstance. Allocate an instance of the specified * class with the specified number of bytes for indexed variables, in * the default zone, using _class_createInstanceFromZone. **********************************************************************/ static id _class_createInstance(Class cls, size_t extraBytes) { return _class_createInstanceFromZone (cls, extraBytes, nil); } static ALWAYS_INLINE id _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, int construct_flags = OBJECT_CONSTRUCT_NONE, bool cxxConstruct = true, size_t *outAllocatedSize = nil) { ASSERT(cls->isRealized()); // Read class's info bits all at once for performance bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor(); bool hasCxxDtor = cls->hasCxxDtor(); bool fast = cls->canAllocNonpointer(); size_t size; size = cls->instanceSize(extraBytes); if (outAllocatedSize) *outAllocatedSize = size; id obj; if (zone) { obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size); } else { obj = (id)calloc(1, size); } if (slowpath(!obj)) { if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) { return _objc_callBadAllocHandler(cls); } return nil; } if (!zone && fast) { obj->initInstanceIsa(cls, hasCxxDtor); } else { // Use raw pointer isa on the assumption that they might be // doing something weird with the zone or RR. obj->initIsa(cls); } if (fastpath(!hasCxxCtor)) { return obj; } construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE; return object_cxxConstructFromClass(obj, cls, construct_flags); } // objc-runtime-new.h // Class's ivar size rounded up to a pointer-size boundary. uint32_t alignedInstanceSize() const { return word_align(unalignedInstanceSize()); } // objc-runtime-new.h size_t instanceSize(size_t extraBytes) const { if (fastpath(cache.hasFastInstanceSize(extraBytes))) { return cache.fastInstanceSize(extraBytes); } size_t size = alignedInstanceSize() + extraBytes; // CF requires all objects be at least 16 bytes. if (size < 16) size = 16; return size; } ``` `CF requires all objects be at least 16 bytes.` 系统为 NSObject 对象分配了至少16个字节大小的空间,但是它使用了 8 个字节大小的空间用来存放 ivars(64位系统) 2. 某个类继承自 NSObject 的情况,内存如何分配