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] 24, 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;
}