Question??

LGPerson *p1 = [LGPerson alloc];
LGPerson *p2 = [p1 init];
LGPerson *p3 = [p1 init];

NSLog(@"%@-%p-%p",p1,p1,&p1);
NSLog(@"%@-%p-%p",p2,p2,&p2);
NSLog(@"%@-%p-%p",p3,p3,&p3);
Copy the code

The running results are as follows:

2021-06-07 00:46:42.553533+0800 alloc explore [26990:394582] <CJPerson: 0x6000023789D0 >- 0x6000023789D0 -0x304e07078 2021-06-07 00:46:42.554203+0800 Alloc explore [26990:394582] <CJPerson: 0x6000023789D0 >- 0x6000023789D0 -0x304e07070 2021-06-07 00:46:42.554282+0800 Alloc explore [26990:394582] <CJPerson: 0x6000023789d0>-0x6000023789d0-0x304e07068Copy the code

It can be concluded that the memory addresses of P1, P2 and P3 are the same, pointing to the same area. So what do alloc and init do at the bottom?

He that will do his work well must first sharpen his tools

  • Download the source code for ObjC from Apple’s open source site (note: the demo used here – objC4-818.2).
  • Compile the source code, refer to this article

Preliminary study of alloc source code

First in the compiled source codemainFunction entry Write a simple code, and then break (Note: -objC4-818.2 is used here)

Then Step into the source code

The first thing we see is the alloc method:

+ (id)alloc {
    return _objc_rootAlloc(self);
}
Copy the code

Internal call to _objc_rootAlloc()

id _objc_rootAlloc(Class cls)
{
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
Copy the code

Enter callAlloc ()

static ALWAYS_INLINE id callAlloc(Class cls, bool checkNil, bool allocWithZone=false) { #if __OBJC2__ if (slowpath(checkNil && ! cls)) return nil; if (fastpath(! cls->ISA()->hasCustomAWZ())) { return _objc_rootAllocWithZone(cls, nil); } #endif // No shortcuts available. if (allocWithZone) { return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil); } return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc)); }Copy the code

_objc_rootAllocWithZone() called after breakpoint debugging

id _objc_rootAllocWithZone(Class cls, malloc_zone_t *zone __unused)
{
    // allocWithZone under __OBJC2__ ignores the zone parameter
    return _class_createInstanceFromZone(cls, 0, nil,
                                         OBJECT_CONSTRUCT_CALL_BADALLOC);
}
Copy the code

_class_createInstanceFromZone()

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 (! Obj ->initInstanceIsa(CLS, hasCxxDtor); 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); }Copy the code

The _class_createInstanceFromZone() method has three core steps:

  • size = cls->instanceSize(extraBytes);Calculate size (internal 16-byte alignment)
  • obj = (id)calloc(1, size);Open the space
  • obj->initInstanceIsa(cls, hasCxxDtor);Associate ISA with CLS

conclusion

Directly attached to the alloC internal execution flow chart: