深入理解 Objective-C:(四) objc_alloc 分配对象空间

314 阅读2分钟

深入理解 Objective-C:(三) 局部对象的内存管理中提到,alloc 被翻译为对objc_alloc 分配存储空间并初始化 isa 指针,本文对 objc_alloc 做个详细的分析。

@autoreleasepool {
       NSObject *obj = [[NSObject alloc] init];
   }

Demo`objc_alloc:
->  0x10088a824 <+0>: nop    
    0x10088a828 <+4>: ldr    x16, #0x17f8              ; (void *)0x00000001c0d6c038: objc_alloc
    0x10088a82c <+8>: br     x16

(lldb) register read x0
      x0 = 0x000000020290f248  (void *)0x000000020290f220: NSObject
(lldb) register read x16
     x16 = 0x00000001c0d6c038  libobjc.A.dylib`objc_alloc

libobjc.A.dylib`objc_alloc:
->  0x1c0d6c038 <+0>:  cbz    x0, 0x1c0d6c050           ; <+24>
    0x1c0d6c03c <+4>:  ldr    x8, [x0]                ;0x000000020290f220
    0x1c0d6c040 <+8>:  and    x8, x8, #0xffffffff8    ;0x000000020290f220
    0x1c0d6c044 <+12>: ldrb   w8, [x8, #0x1d]   ;ldrb w8, 0x000000020290f23d (w8=0xe0)
    0x1c0d6c048 <+16>: tbz    w8, #0x6, 0x1c0d6c054     ; <+28> 0b 0110
    0x1c0d6c04c <+20>: b      0x1c0d62548               ; _objc_rootAllocWithZone
    0x1c0d6c050 <+24>: ret    
    0x1c0d6c054 <+28>: adrp   x8, 211229
    0x1c0d6c058 <+32>: add    x1, x8, #0x469            ; =0x469 
    0x1c0d6c05c <+36>: b      0x1c0d495c0               ; objc_msgSend
  • <+0> x0 == nil,传入的类对象为空,跳转到 <+24> 直接退出
  • <+4> 加载元类对象 isa 到 x8
  • <+8> 通过 ISA_MASK 取 isa 中类对象的引用到 x8
  • <+12> isa 偏移 29字节处的一个字节(0xe0 这个值和类对象有关)到 w8 (0123 56)
  • <+16> 如果 w8 == #0x6,跳转到 <+28>
  • <+20> 跳转到 _objc_rootAllocWithZone 分配 NSObject 实例对象空间
  • <+24> 返回
  • <+28>-<+32> 读取选择器 alloc/allocWithZone:
  • <+36> 调用类对自定义的 alloc/allocWithZone:

<+16> 语义分析

#define FAST_CACHE_REQUIRES_RAW_ISA   (1<<13)  
// class or superclass has default alloc/allocWithZone: implementation
// Note this is is stored in the metaclass.
#define FAST_CACHE_HAS_DEFAULT_AWZ    (1<<14)    
// class or superclass has default new/self/class/respondsToSelector/isKindOfClass
#define FAST_CACHE_HAS_DEFAULT_CORE   (1<<15)  

struct cache_t {
public:
    explicit_atomic<uintptr_t> _bucketsAndMaybeMask;//8
    union {
        struct {
            explicit_atomic<mask_t>    _maybeMask;//4
#if __LP64__
            uint16_t                   _flags;//4
#endif
            uint16_t                   _occupied;
        };
        explicit_atomic<preopt_cache_t *> _originalPreoptCache;
    };
...
}

NSObject 元类对象的 struct cache_t 中的 _flags 字段占据类对象的[28]和第[29]字节,ldrb w8, [x8, #0x1d] 读取的是[29]字节,0xe0 = 0b11100000,即 FAST_CACHE_REQUIRES_RAW_ISA 、FAST_CACHE_HAS_DEFAULT_AWZ、FAST_CACHE_HAS_DEFAULT_CORE。

如果类对象或元类对象实现了默认的 alloc/allocWithZone,跳转到 <+28>,走消息发送机制,用类对象自己定义的内存分配函数

小结

iOS 默认使用运行时定义的内存分配器 _objc_rootAllocWithZone 。但是系统也为程序设计者预留了可能性,即通过消息机制实现类系的个性化内存分配器。