The alloc method is a necessary step to create an object. We usually use alloc directly to create an object. So how to implement the underlying alloc method? What methods are called during this process? What does each method do? So with that in mind how is alloc actually implemented at the bottom?
The preparatory work
- This article explores the underlying principle of the main method is: source code, assembly, breakpoint debugging, LLDB debugging
- Apple source
- opensource.apple.com/
- opensource.apple.com/tarballs/
- This article sample code address (including compiled source code) : gitee.com/jrcode/ios_…
Alloc flow analysis
Locate source code
LGPerson *p1 = [LGPerson alloc];
Copy the code
- Place a breakpoint at the above code location, execute to the breakpoint location, and hold
control+step into
, enter assembly
- So here we see the call first
objc_alloc
Method, but it is difficult to follow the process, in which case we can use symbolic breakpoints - Add sign breakpoint
objc_alloc
And continue to execute
- As can be seen from the running results
objc_alloc
Methods in thelibobjc.A.dylib
In the dynamic library, i.eobjc
The source code- The next call is
_objc_rootAllocWithZone
andobjc_msgSend
Look at the alloc process through the source code
- It’s been located
objc_alloc
Method, search directly in the source code projectobjc_alloc(
, locate theobjc_alloc
Method implementation location inNSObject.mm
In the file
// Calls [cls alloc].
id
objc_alloc(Class cls)
{
return callAlloc(cls, true/*checkNil*/.false/*allocWithZone*/);
}
Copy the code
- As can also be seen from the comments in the code above, the call
alloc
Method is actually calledobjc_alloc
And then callcallAlloc
methods
// Call [cls alloc] or [cls allocWithZone:nil], with appropriate
// shortcutting optimizations.
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
- In the above method, there is no way to determine what is being called
_objc_rootAllocWithZone
orobjc_msgSend
, how to determine the execution process next?- Method one: because what we’re debugging works
objc
Source code, so you can directly add breakpoints in the source code to debug the execution process - Method two: assembly and process combine symbolic breakpoints
- Note: Since breakpoints may also be called on objects created during system initialization, you need to disable breakpoints when executing to
**[LGPersion alloc]**
To enable the breakpoint
- Method one: because what we’re debugging works
Dynamic debugging
First use method two: assembly and flow combine symbol breakpoints
- To perform to
[LGPerson alloc]
At the breakpoint of thecontrol+step into
Enter the assembly - Lower sign breakpoint
objc_alloc
, and continue to execute toobjc_alloc
- Step down, and you can see what’s called
objc_msgSend
Rather than_objc_rootAllocWithZone
- Perform to
objc_msgSend
, read the current register, you can see, here is calledalloc
methods- Register read: Reads the current register information
- Register Read X0: The X0 register holds the message receiver
- Register read x1: The SEL is stored in register X1
- From the above debugging flow, you can see the calling flow:
- objc_alloc
- msgSend
- alloc
Continue with method one: source add breakpoint debugging process
- To perform to
[LGPerson alloc]
Add breakpoints to the source code below, and then execute the flow
- Through breakpoint debugging, you can determine the source code call flow:
- objc_alloc
- callAlloc
- return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc));
- alloc
- _objc_rootAlloc
- callAlloc
- _objc_rootAllocWithZone
- _class_createInstanceFromZone
- InstanceSize: Calculates the memory usage of objects
- Calloc: Opens up memory and returns the address
- InitInstanceIsa: initializes the ISA and associates it with the class
- return obj; Return object address