在深入理解 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 。但是系统也为程序设计者预留了可能性,即通过消息机制实现类系的个性化内存分配器。