Only blame our love so turbulent, love so deep, so the dream woke up stranded silent waved, but can not return to god, if at the beginning of the meeting can hold back the excited soul, maybe tonight I will not let their destruction in the missing… Ahem, that’s the end of the song, and today we’re going to look at Alloc, the most familiar stranger.

Source code analysis

In Xcode, clicking on alloc just goes into objc/ nsobject. h to see the method declaration, and we don’t know what’s going on inside. However, Apple provides objC source code, which is not the most cool, there is more cool, cool fine god compilable objC source code, we can compile and run, breakpoint debugging.

Through the source code, click into alloc to go through the following process

+ (id)alloc {
    return _objc_rootAlloc(self);
}
Copy the code
_objc_rootAlloc(Class cls)
{
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
Copy the code

__OBJC2__ is the logic that determines whether it is objC2.0, compatible with objC1.0, and is now objC2.0

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(Class cls, malloc_zone_t *zone __unused)
{
    // allocWithZone under __OBJC2__ ignores the zone parameter
    return _class_createInstanceFromZone(cls, 0, nil,
                                         OBJECT_CONSTRUCT_CALL_BADALLOC);
}
Copy the code

But when we use the real machine debugging, breakpoint into assembly view, found not to go to alloc but objc_alloc, go to source search objc_alloc

objc_alloc(Class cls)
{
    return callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/);
}
Copy the code

After setting a breakpoint in the objc_alloc function, we find that the final alloc flow is

Why go objc_alloc alloc, via the source, we found a function fixupMessageRef, this function the alloc and allocWithZone, retain, release, autorelease method such as IMP has changed, FixupMessageRef is called in _read_images, which is called at compile time, indicating that in LLVM, the IMP of this method is changed.

Internal alignment of the structure

The principle of internal alignment exists in the structure

  1. The data member of a struct (or union), the first data member is placed at offset 0, and the starting position of each data member is from the size of the member or the size of the member’s children (as long as the member has children, such as arrays). Structure, etc.) (for example, if int is 4 bytes, it is stored from the address that is a multiple of 4.
  2. Struct as members: If a structure has some struct members, the struct members are stored from an integer multiple of the size of the largest element in the structure. The size of the member structure is its own aligned size.
  3. The total sizeof the structure, the result of sizeof, must be an integer multiple of the largest member within the structure.

practice

struct Struct1 { double a; // 8 [0 7] char b; // 1 [8] int c; // 4 (9 10 11 [12 13 14 15] short d; // 2 [16 17] 24 }struct1; struct Struct2 { double a; // 8 [0 7] int b; // 4 [8 9 10 11] char c; // 1 [12] short d; // 2 (13 [14 15] 16 }struct2; struct Struct3 { double a; // 8 [0 7] int b; //4 [8 9 10 11] char c; // 1 [12] short d; // 2 (13 [14 15] int e; // 4 [16 17 18 19] struct Struct1 str; // 8 (20 21 22 23 [24 ~ 47] 48}struct3; The size of the aligned Struct1 calculated above is 24, and the size of the Struct1 as a member is 24.Copy the code

OC Specifies the size of the object

There are two functions to calculate the size of an OC object, class_getInstanceSize and malloc_size, but they sometimes compute different results for the same object. Let’s look at the differences.

class_getInstanceSize

Class_getInstanceSize is a runtime method that can be internally implemented by looking at objC’s source code. Click in and we’ll go to the method below

uint32_t alignedInstanceSize() const {
        return word_align(unalignedInstanceSize());
    }
Copy the code

UnalignedInstanceSize () calculates an unaligned size for word_align. Click unalignedInstanceSize()

// May be unaligned depending on class's ivars. uint32_t unalignedInstanceSize() const { ASSERT(isRealized()); return data()->ro()->instanceSize; } Computes the sum of the sizes of member variables contained in the classCopy the code

Click to go to word_align

static inline uint32_t word_align(uint32_t x) { return (x + WORD_MASK) & ~WORD_MASK; } WORD_MASK is a macro definition, 7 in 64-bit architecture, this is an 8-byte alignment algorithm if: x = 18 18 + 7 = 25 = 0001 1001 7 = 0000 0111 ~ 7 = 1111 1000 0001 1000 = 24Copy the code

Class_getInstanceSize is a calculation of the sum of the member variables of a class, followed by 8-byte alignment, resulting in the size of the object needed in memory.

malloc_size

Malloc_size returns the true size of an object in the heap. Using malloc’s source code, we can explore how objects can make heap size.

void *p = calloc(1, 20); NSLog(@"%lu",malloc_size(p));Copy the code

And then finally you see an algorithm that looks like this

k = (size + NANO_REGIME_QUANTA_SIZE - 1) >> SHIFT_NANO_QUANTUM; slot_bytes = k << SHIFT_NANO_QUANTUM; SHIFT_NANO_QUANTUM 4 NANO_REGIME_QUANTA_SIZE 1 << 4 = 16 20 + 16 -1 = 35 = 0010 0011 then move 4 bits right, then move 4 bits left, 0010 0011 >> 4 = 0000 0010 0000 0010 << 4 = 0010 0000 = 32 This algorithm is a 16-byte alignment algorithmCopy the code

So, the actual amount of memory the object opens up is 16-byte aligned.

conclusion

Each object contains at least one member variable isa, which is 8 bytes. In most cases, we create objects that add member variables. So, apple does 16-byte alignment by default when actually opening up heap memory. This design does not compress the object space very much, and it wastes less memory (compared to 32-byte alignment, etc.). Apple’s two algorithms are very good when it comes to byte alignment, and we can look at this bit algorithm.

For example, 16-byte alignment, two algorithms can be used

  1. x + 16 – 1 & ~(16 – 1)
  2. (x + 16 – 1) >> 4 << 4