1. Preparations:

Apple open source code address:

opensource.apple.com/

Opensource.apple.com/tarballs/ob…

MacOS11.01 objC4-818.2

Github.com/longyilang/…

2. Three ways to debug breakpoints, using breakpoint alloc as an example:

2.1 Method 1:

  • Start by adding the location of the breakpoint in your code (in this case, the line of Person’s alloc).
  • Then add an “alloc” breakpoint and set it to a light-colored disabled state (since there are many places to invoke the alloc method, we need the breakpoint to execute exactly into Person’s alloc method).

  • When the breakpoint executes at line 6, set the “alloc” symbol breakpoint to work, and click the breakpoint execute button to switch to the flow shown below. You can see that the Person class calls the alloc method from libobjc.a.dylib +[NSObject alloc]. The next flow inside the alloc method is to jump to the _objc_rootAlloc method. To do this, go to the objC open source library at the source address above and find the _objc_rootAlloc method to see the implementation.

2.2 Method 2:

  • Set the [Person Alloc] breakpoint on line 6, and when the breakpoint is executed, hold down the Ctrl mouse and click the Step into button in the breakpoint toolbar to get the following result, indicating that the method to be called is objc_alloc

  • The objc_alloc method comes from libobjc.a.dilib. For this, we can also find the objC open source library in the source address above and find the method

2.3 Method 3:

  • Set the [Person Alloc] breakpoint at line 6. When the breakpoint is executed at this point, go to the Xcode menu bar and select Debug->DebugWorkFlow->Awalys Show Disassembly. The next step is to add the objc_Alloc symbol breakpoint. To find the source of the objc_alloc method

3. Alloc and New flow chart

4. Byte alignment and memory alignment

4.1 Structure member variables are 8-byte aligned

  • Let’s start with a snippet of code, implemented in main.m:
@interface Person : NSObject{
    @public NSString *name;
    @public int age;
    @public char a;
}

int main(int argc, const char * argv[]) {
    Person *p = [Person alloc];
    p->name = @"LY";
    p->age = 18;
    p->a = 'a';
    NSLog(@"--->%zu",class_getInstanceSize(p.class));
    return 0;
}
Copy the code
  • The following output is displayed:

  • Question:

    (1) Why is the size of the class_getInstanceSize instance object 24 bytes?

    (2) Why does an 8-byte address segment 0x0000006100000012 store two values since it is 8-byte aligned?

  • Specific analysis:

    (1) First, the lower level C/C++ code is restored by clang-rewrite-objc main.m -o main.cpp in the terminal as follows:

typedef struct objc_class *Class;

struct NSObject_IMPL {
    Class isa;
};

struct Person_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    NSString *name;
    int age;
    char a;
};
Copy the code

Struct NSObject_IMPL NSObject_IVARS is the member variable isa inherits from NSObject. Isa isa Class type. Class is just an alias, which is essentially a pointer type. So it’s 8 bytes; NSString *name is a pointer that’s 8 bytes long; Int age is 4 bytes; Char a is 1 byte;

x = 8+8+4+1 = 21

(3) class_getInstanceSize() this method returns the size of an instance of a class. It can be seen from the alloc initialization flowchart in step 3 that an 8-byte alignment algorithm is processed in the word_align(x) method:

Alignment algorithm :(x+7) &~7; (21 + 7) & ~ 7 = 24;

(4) Because apple has optimized the storage itself, it would not be too wasteful to let a character occupy an 8-byte pit, so we combined char A and int age together, that is, memory alignment by 8 bytes; There are two reasons for 8-byte alignment. One is that the largest data-type placeholder on a 64-bit processor is 8 bytes, and the other is for efficient, rule-based data reading.

  • Structure size alignment principle:

(1): Alignment rules for data members: Struct (or union) data members, the first data member is placed at offset 0, then the starting position of each data member is stored from the size of the member or the size of the member’s children (as long as the member has child members, such as arrays, Structure, etc.) (for example, if int is 4 bytes, it is stored from the address that is a multiple of 4. Min (current starting position mn)m=9 n=4 9 10 11 12

(2) struct as members: If a struct contains some members, then the members are stored from an integer multiple of the size of the largest element in the struct.(struct A contains char,int,double, etc., then b is stored from an integer multiple of 8.)

(3): finishing work: the total sizeof the structure, which is the result of sizeof. Must be an integer multiple of its largest internal member. What is lacking must be made up.

The 4.2 Calloc () heap area is cleared with 16-byte alignment

  • Let’s look at one more piece of code
int main(int argc, const char * argv[]) {
// create a 21-byte space and assign it to pointer p;
void *p = calloc(1.21);
// Get the size of p in the heap
NSLog(@"---->%lu",malloc_size(p));
    return 0;
}
Copy the code
  • The output is as follows

  • Question: Why is the output 32? Instead of 21?
  • Analysis:

Take a look at the calloc source code flow, and the final result is to get the actual size required to perform a 16-self alignment operation, so the size in the heap is 32 bytes

  • Note: the next source code for libmalloc is recommended: github.com/LGCooci/obj… Once you get the code you can run, follow the steps in the flowchart above and follow the breakpoints. Everything will be clear.