runtime01 - 对象内存布局
Obj-C NSObject对象的内存布局是怎么样的? 占据多少内存
实际上类似一个只包含一个成员变量isa指针的结构体
struct NSObject_IMPL { Class isa; } 复制代码
Obj-C NSObject对象占据多少内存
有8字节就够用, 但是在alloc的时候, 系统会根据 对象的instancesize 和 16来取最大值, 所以也会申请16字节的大小
一个普通对象的内存布局是怎么样的
struct NSObject_IMPL { Class isa; }; struct Person_IMPL { struct NSObject_IMPL NSObject_IVARS; int _age; }; struct Student_IMPL { struct Person_IMPL Person_IVARS; long long _height; }; 复制代码
@interface Person: NSObject { int _age; } @end @interface Student: Person { long long _height; } @end 复制代码
Demo
// xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main_arm64.cpp #import <Foundation/Foundation.h> #import <objc/runtime.h> #import <malloc/malloc.h> struct NSObject_IMPL { Class isa; }; struct Person_IMPL { struct NSObject_IMPL NSObject_IVARS; int _age; }; struct Student_IMPL { struct Person_IMPL Person_IVARS; long long _height; }; @interface Person: NSObject { @public int _age; } @end @implementation Person @end @interface Student: Person { @public long long _height; } @end @implementation Student @end int main(int argc, const char * argv[]) { @autoreleasepool { // allocWithZone:时分配给对象的最小空间为16, 不足16的, 也会返回16 // 为了效率, iOS分配给对象的空间都是16的倍数 // class_getInstanceSize 获取对象需要的最小空间 // malloc_size 获取对象真实的占用空间 NSObject *obj = [NSObject new]; NSLog(@"%zu, %zu", class_getInstanceSize([NSObject class]), // 只有一个isa指针, 所以只需要8 malloc_size((__bridge const void *)obj)); // allocWithZone:时分配给对象的最小空间为16, 不足16的, 也会返回16 Person *person = [Person new]; NSLog(@"%zu, %zu", class_getInstanceSize([Person class]), // 只有一个isa指针,和一个int指针, 但是需要内存对齐, 所以需要16 malloc_size((__bridge const void *)person)); // allocWithZone:时分配给对象的最小空间为16, 不足16的, 也会返回16 Student *student = [Student new]; NSLog(@"%zu, %zu", class_getInstanceSize([Student class]), // 因为内存对齐的原因, 需要24 malloc_size((__bridge const void *)student)); // iOS分配给对象的空间都是16的倍数, 所以是32 student->_height = 100; student->_age = 50; struct Student_IMPL *stu = (__bridge struct Student_IMPL *)(student); } return 0; } // **2021-09-27 11:09:37.980596+0800 TestOC[40849:5211544] 8, 16** // **2021-09-27 11:09:37.980885+0800 TestOC[40849:5211544] 16, 16** // **2021-09-27 11:09:37.980923+0800 TestOC[40849:5211544] 32, 32** 复制代码
源码
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); } inline 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; }
作者:潘森
链接:https://juejin.cn/post/7025891345965252645