What is the memory layout of the Obj-C NSObject object? How much memory is occupied

It is actually like a structure containing only a pointer to the member variable ISA

struct NSObject_IMPL {
    Class isa;
}
Copy the code

Obj -c how much memory NSObject takes up

8 bytes is enough, but when alloc is applied, the system will take the maximum value based on the instancesize and 16 of the object, so 16 bytes will be applied

What is the memory layout of a normal object

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;
};
Copy the code
@interface Person: NSObject
{
    int _age;
}
@end
@interface Student: Person
{
    long long _height;
}
@end
Copy the code

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: the minimum space allocated to the object at time is 16, if less than 16, 16 is returned
        // For efficiency, iOS allocates space to objects in multiples of 16
        // class_getInstanceSize gets the minimum space required by the object
        // malloc_size Gets the actual space occupied by the object

        NSObject *obj = [NSObject new];
        NSLog(@"%zu, %zu",
              class_getInstanceSize([NSObject class]), // There is only one ISA pointer, so only 8 is needed
              malloc_size((__bridge const void *)obj)); // allocWithZone: the minimum space allocated to the object at time is 16, if less than 16, 16 is returned

        Person *person = [Person new];
        NSLog(@"%zu, %zu",
              class_getInstanceSize([Person class]),  // There is only one isa pointer and one int pointer, but memory alignment is required, so 16 is required
              malloc_size((__bridge const void *)person)); // allocWithZone: the minimum space allocated to the object at time is 16, if less than 16, 16 is returned

        Student *student = [Student new];
        NSLog(@"%zu, %zu",
              class_getInstanceSize([Student class]), // For memory alignment reasons, 24 is required
              malloc_size((__bridge const void *)student)); // iOS allocates space to objects in multiples of 16, so 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 * *


Copy the code

The source code

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(a);bool hasCxxDtor = cls->hasCxxDtor(a);bool fast = cls->canAllocNonpointer(a);size_t size;

// Pay attention to this method
    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;
}
Copy the code