alloc 调用流程
添加符号断点
objc开源代码
开源地址:opensource.apple.com/tarballs/
1、libobjc.A.dylib`+[NSObject alloc]:
//step into instruction
2、001-alloc&init探索`objc_alloc:
3、0x10d086c10 <+64>: callq 0x10d0873d0; symbol stub for: objc_alloc
graph TD
下符号断点 --> 符号断点查看源码;
control-step-into --> 符号断点查看源码;
汇编查看 --> 符号断点查看源码;
graph LR
A[alloc] --> B(_objc_rootAlloc)
B --> C{callAlloc}
C --> |OBJC2宏| E(_objc_rootAllocWithZone)
C --> |不是OBJC2宏| D(objc_msgSend)
E --> F(_class_createInstanceFromZone)
graph LR
A[_class_createInstanceFromZone] --> B(cls->instanceSize)--> E(计算出内存空间大小)
A --> C[callAlloc] -->F[向系统申请开辟内存 返回地址指针]
A --> D(obj->initInstanceIsa)-->G[关联到相应的类]
//方法1 要开辟多少内存
size = cls->instanceSize(extraBytes);
//内存对齐
/**
8 + 15 = 23
16 + 7
0000 0000 0001 0111 23
1111 1111 1111 0000 15的取反
0000 0000 0001 0000 16倍数
**/
static inline size_t align16(size_t x) {
return (x + size_t(15)) & ~size_t(15);
}
init
+ (id)init {
return** (id)self; //工厂设计方法,做一些数据初始化,提供构造方法入口
}
new
+ (id)new {
return [callAlloc(self, false/*checkNil*/) init];
}
new使用上没有区别,存在不同的点: 使用类可能通过重写init方法,做其他数据的的初始化,使用new无法调用init构造方法
对象内存结构探索
TGPerson *objc1 = [TGPerson alloc];
objc1.name = @"TAN";
objc1.nickName = @"KE";
=========输出结果=============
(lldb) x objc1
0x10065eee0:fd21000001801d001010000001000000
0x10065eef0:30100000010000000000000000000000
(lldb) x/4gx objc1
0x10065eee0: 0x001 d8001000021fd 0x0000000100001010
0x10065eef0: 0x0000000100001030 0x0000000000000000
(lldb) po 0x0000000100001010
TAN
(lldb) po 0x0000000100001030
KE
x/4gx p
x /nuf <addr>
n表示要显示的内存单元的个数
v
u表示一个地址单元的长度:
b表示单字节
h表示双字节
w表示四字节
g表示八字节.
f表示显示方式,可取如下值:
x按十六进制格式显示变量
d按十进制格式显示变量
u按十进制格式显示无符号整型
o按八进制格式显示变量
t按二进制格式显示变量
a按十六进制格式显示变量
i指令地址格式
C按字符格式显示变量
f按浮点数格式显示变量 //p/f 打印16进制的浮点类型