Write in the front: the exploration of the underlying principles of iOS is my usual development and learning in the continuous accumulation of a step forward road. I hope it will be helpful for readers to record my journey of discovery.Copy the code

Summary column of content

  • Summary of the phase of iOS underlying principle exploration

sequence

As an iOS developer, we use alloc to create all the objects in our daily development work. So what does the alloc layer do? I’m going to go step by step into the underlying implementation of the alloc method.

A preliminary study

Let’s look at the following code first

    SMPerson *p1 = [SMPerson alloc];
    SMPerson *p2 = [p1 init];
    SMPerson *p3 = [p1 init];
    
    NSLog(@"%@-%p-%p", p1, p1, &p1);
    NSLog(@"%@-%p-%p", p2, p2, &p2);
    NSLog(@"%@-%p-%p", p3, p3, &p3);
Copy the code

Print content:

    <SMPerson: 0x600000710400>-0x600000710400-0x7ffee6f15088
    <SMPerson: 0x600000710400>-0x600000710400-0x7ffee6f15080
    <SMPerson: 0x600000710400>-0x600000710400-0x7ffee6f15078
Copy the code

As you can see, the init method does nothing to the memory space after SMPerson alloc it from the system. The address pointer is created from the alloc method. As follows:

Note: If you are careful, you must have noticed that P1, P2, and P3 are all 8 bytes off. This is because the pointer memory space size is 8 bytes, P1, P2, P3 are from the stack memory space, and the stack memory space is contiguous. At the same time, they all point to the same memory location.

So, how does alloc open up memory space?

First of all, the first response is, “Jump to Definition,

As a result, Xcode doesn’t have the ability to jump directly to the underlying implementation, so that’s not what we want.

In the ground

Here are three ways to find out:

Method 1

Since it is not possible to jump directly to the API documentation to see the internal implementation of alloc, we can also explore how it is implemented by following symbolic breakpoints.

That’s where we’re going

A library called Libobjc.a. dylib. At this point, we should go to apple’s open source library to find the answers we want.

Click here for a summary of Apple’s open source

Method 2

Or we can just put a breakpoint on the alloc line, and when we get to that point, hold down the Control key and hit Step into, and then we go in here

We can see an objc_alloc function method called, and then we have a symbolic breakpoint, and again, we find libobjc.a. dylib.

Methods 3

In addition, we can still debug and find the corresponding implementation through assembly, and the breakpoint is still on the alloc line.

Debug > Debug Workflow > Always Show Disassembly

Find the line where the callq method is called,

And then step into, we find the call to objc_alloc, and then we do the same thing as we did in method 2, and finally, we find libobjc.a. dylib.

Deep investigation

Download the source objC4-818.2

Next, analyze the source code.

This is where the alloc method is called

Next is a call to _objc_rootAlloc

And then we call callAlloc

The breakpoint leads to _objc_rootAllocWithZone

After is _class_createInstanceFromZone

This approach is key

In the _class_createInstanceFromZone method, which is a class initialization process, there are three important points

The first is:
Size = CLS ->instanceSize(extraBytes);Copy the code

The internal implementation is as follows:When calculating the size of the memory space, will callcache.fastInstanceSize(extraBytes)Method,

Finally, the method align16(size + extra-fast_cache_alloc_delta16) is called. The implementation of ALIGN16 is as follows:

static inline size_t align16(size_t x) {
    return (x + size_t(15)) & ~size_t(15);
}
Copy the code

As you can see, the system performs 16 bytes of alignment, which means that an object has at least 16 bytes of memory.

Here we take an example: size_t x = 8; Then the size calculation after the align16 operation is as follows:

    (8 + 15) & ~15;
    
    0000 0000 0000 1000     8
    0000 0000 0000 1111     15  
    
=   0000 0000 0001 0111     23
    1111 1111 1111 0000     ~15
    
=   0000 0000 0001 0000     16

Copy the code
The second is:
/// Return the address pointer; obj = (id)calloc(1, size);Copy the code
The third is:
Obj ->initInstanceIsa(CLS, hasCxxDtor); obj->initInstanceIsa(CLS, hasCxxDtor);Copy the code

Conclusion:

So, to conclude, the underlying alloc call flow is as follows:

In this process, the system creates a class object for us.