I. Problem thinking:
QZPerson *p1 = [QZPerson alloc]; QZPerson *p2 = [p1 init]; QZPerson *p3 = [p1 init]; NSLog(@"%@- memory address %p- pointer address %p",p1,p1,&p1); NSLog(@"%@- memory address %p- pointer address %p",p2,p2,&p2); NSLog(@"%@- memory address %p- pointer address %p",p3,p3,&p3); Note: p1 prints the memory header of the object; &p1 prints the first address of the memory pointer p1 itself.Copy the code
The printed result is:
<QZPerson: 0x6000025C0AC0 >- Memory address 0x6000025C0AC0 - Pointer address 0x7ffEE67AE0c8 <QZPerson: 0x6000025C0AC0 >- Memory address 0x6000025C0AC0 - Address of pointer 0x7FFEE67AE0C0 <QZPerson: 0x6000025C0AC0 >- Memory address 0x6000025C0AC0 - Address of pointer 0x7FFEE67AE0B8Copy the code
Conclusion:
- 1. The memory address space of the three objects is the same. Indicates that the space of the object is created from alloc.
- 2. Stack memory is contiguous. Pointer addresses differ by 8 bytes each.
Consider: Alloc opens up memory, so what is the specific flow of alloc?
Two, the bottom of the three methods of exploration
1, the form of the symbol breakpoint directly with the process
Dblib '+[NSObject alloc]; dblibobjc.a.lib' +[NSObject alloc]; dblibobjc.a.lib '+[NSObject alloc]; 2) Click step info to enter libobjc.a.dylib '_objc_rootAlloc:Copy the code
2. Breakpoint by pressing Control-step into
1) Use the breakpoint alloc and control-step into objc_alloc eg: 001-alloc&init to explore 'objc_alloc: Libobjc.a.dylib 'objc_alloc: 3) then go to libobjc.a.dylibCopy the code
3, assembly view with process, view the source code
Debug -> Debug Workflow -> Always Show Disassembly: 0x10A98bd7e movq 0x76d3(%rip), %rcx ; (void *)0x000000010a993548: QZPerson 0x10a98bd85 <+165>: movq %rcx, %rdi 0x10a98bd88 <+168>: callq 0x10a98c3a6 ; Symbol Stub for: objc_alloc 3) Control-step into to locate objc_alloc eg:001-alloc&init Explore 'objc_alloc: 4) Libobjc.a.dylib can be located via the breakpoint objc_allocCopy the code
Apple open source library
Apple source code: openSource.apple.com
This address with a more direct opensource.apple.com/tarballs/
3. Exploration and study of alloc process
alloc
+ (id)alloc {
return _objc_rootAlloc(self);
}
Copy the code
Methods _objc_rootAlloc
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
Copy the code
Methods callAlloc
callAlloc(Class cls, bool checkNil, Bool allocWithZone=false) {#if __OBJC2__ // select fastPath and slowpath from objc2.0 (slowpath(checkNil && ! cls)) return nil; If (fastPath (!) {// 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
Methods _objc_rootAllocWithZone
id
_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
Core flow _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) {// Initialize isa pointer with CLS. 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
You can see from the flowchart and source code that there are three core methods that need to be implemented in the _class_createInstanceFromZone method
- CLS ->instanceSize: Calculate memory size 8 bytes alignment See the next chapter for memory alignment
- (id)calloc(1, size) : open memory, return address pointer
- Obj ->initInstanceIsa: initializes the pointer associated with the class
instanceSize
uint32_t alignedInstanceSize() const { return word_align(unalignedInstanceSize()); } 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; // The memory size must be at least 16 bytes. }Copy the code
Word_align 8 bytes align: (x + 7) & (7 = inverse)
#ifdef __LP64__ # define WORD_SHIFT 3UL # define WORD_MASK 7UL # define WORD_BITS 64 #else # define WORD_SHIFT 2UL # define WORD_MASK 3UL # define WORD_BITS 32 #endif static inline uint32_t word_align(uint32_t x) { return (x + WORD_MASK) & ~WORD_MASK; } static inline size_t word_align(size_t x) {return (x + WORD_MASK) & ~WORD_MASK; } static inline size_t align16(size_t x) {return (x + size_t(15)) & ~size_t(15); // 16 bytes aligned}Copy the code
4. Draw the alloc flow chart
Note: source objC4-818.2;
To be continued