One, the actual use

NBPerson * person1 = [NBPerson alloc]; NBPerson * person2 = [person1 init]; NBPerson * person3 = [person1 init]; NBPerson * person4 = [NBPerson alloc]; NSLog(@"%@---%p--%p",person1,person1,&person1); NSLog(@"%@---%p--%p",person2,person2,&person2); NSLog(@"%@---%p--%p",person3,person3,&person3); NSLog(@"%@---%p--%p",person4,person4,&person4); **2021-07-17 20:56:11.522447+0800 alloc_ Probe [953:28200] <NBPerson: 0x600002e44410>-- 0x7ffee8177158** **2021-07-17 20:56:11.522676+0800 alloc_ Probe [953:28200] <NBPerson: 0x600002e44410>-- 0x7ffee8177150** **2021-07-17 20:56:11.522915+0800 alloc_ Probe [953:28200] <NBPerson: 0x600002e44410>-- 0x600002e44410--0x7ffee8177148** **2021-07-17 20:56:11.523478+0800 alloc_ Probe [953:28200] <NBPerson: 0x600002e44420>---0x600002e44420--0x7ffee8177140**Copy the code

To observe the

  1. Person1, Person2, and Person3 have the same memory address and person4 has different memory addresses.
  2. Person1, Person2, person3, person4, pointer addresses are different
  3. Person1, Person2, and person3 have smaller memory addresses than person4
  4. Person1, Person2, person3, person4 pointer addresses, getting smaller and smaller

figure

graph TD
&person1-0x7ffee8177158 --> alloc1-0x600002e44410
&person2-0x7ffee8177150 --> alloc1-0x600002e44410
&person3-0x7ffee8177148 --> alloc1-0x600002e44410
&person4-0x7ffee8177140 --> alloc2-0x600002e44420


conclusion

  1. Alloc opens up the actual memory (heap), init does not open up memory
  2. The heap address is from the bottom to the top, and the stack address is from the top to the bottom

Two, exploring the bottom must be able to

  1. Breakpoint debugging
  2. Xcode->Debug->Debug Workflow->Always Show Disassembly

Three, source exploration

  1. Source objc – 818.2
  2. Open source
  3. Began to explore
  • Global search alloc {to find the code
+ ( id )alloc {

    return  _objc_rootAlloc(self);

}
Copy the code
  • _objc_rootAlloc
**id**

_objc_rootAlloc(Class cls)

{

    return callAlloc(cls, false/*checkNil*/.true/*allocWithZone*/);

}
Copy the code
  • callAlloc
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
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone){ **id** obj; A \ * *if** (fastpath(! zone)) { obj = class_createInstance(cls,0); } * *else** {

        obj = class_createInstanceFromZone(cls, 0, zone); } \ * *if** (slowpath(! obj)) obj = _objc_callBadAllocHandler(cls); 天安门事件return** obj;

}
Copy the code
  • ob’j’c-runtime-new.mm
  • _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* * (! 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);

}
Copy the code
  • InstanceSize calculates the memory size
**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
  • fastInstanceSize
size_t fastInstanceSize(size_t extra) **const** { ASSERT(hasFastInstanceSize(extra)); A \ * *if** (__builtin_constant_p(extra) && extra == 0) {

            **return** _flags & FAST_CACHE_ALLOC_MASK16;

        } else {

            size_t size = _flags & FAST_CACHE_ALLOC_MASK;

            // remove the FAST_CACHE_ALLOC_DELTA16 that was added

            // by setFastInstanceSize

            returnalign16(size + extra - FAST_CACHE_ALLOC_DELTA16); }}Copy the code
  • Align16 16 bytes aligned
static inline size_t align16(size_t x) {

    return (x + size_t(15)) & ~size_t(15);

}
Copy the code
  • Calloc opens up memory return address pointer

  • Initializes the pointer and associates the class

inline void 
objc_object: :initInstanceIsa(Class cls, bool hasCxxDtor){ ASSERT(! cls->instancesRequireRawIsa()); ASSERT(hasCxxDtor == cls->hasCxxDtor()); initIsa(cls,true, hasCxxDtor);
}
Copy the code
  • Init inquiry
- (id)init {
    return _objc_rootInit(self);
}
Copy the code
  • Init returns itself mainly to be overridden by subclasses
id
_objc_rootInit(id obj)
{
    // In practice, it will be hard to rely on this function.
    // Many classes do not properly chain -init calls.
    return obj;
}
Copy the code
  • New inquiry alloc + init
+ (id)new {
    return [callAlloc(self, false/*checkNil*/) init];
}
Copy the code

Iv. Flow chart

graph TD
alloc --> _objc_rootAlloc -->callAlloc --> _objc_rootAllocWithZone --> _class_createInstanceFromZone --> instanceSize
_class_createInstanceFromZone --> calloc
_class_createInstanceFromZone --> initInstanceIsa
callAlloc --> _objc_msgSend