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
- Person1, Person2, and Person3 have the same memory address and person4 has different memory addresses.
- Person1, Person2, person3, person4, pointer addresses are different
- Person1, Person2, and person3 have smaller memory addresses than person4
- 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
- Alloc opens up the actual memory (heap), init does not open up memory
- 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
- Breakpoint debugging
- Xcode->Debug->Debug Workflow->Always Show Disassembly
Three, source exploration
- Source objc – 818.2
- Open source
- 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