0x000 从哪里入手?
先看看main函数
0x001 初探?
- 为什么是 alloc init?
- alloc init 做了什么?
热身:先来打印一些信息:
屏幕快照 2019-12-20 下午7.03.52.png
热身疑问:
alloc 已经创建了对象,为什么还要有init?
alloc 怎么创建的?
alloc 也看不到源码,但是我们需要了解alloc 的源码实现?
如何快速探索出Object-C一个方法的底层所在实现
通过上述方法的探索,能知道 alloc 的底层实现就是
libobjc.A.dylib 'objc_alloc'
0x002 源码初解:libobjc.A.dylib 'objc_alloc'
苹果开源源码objc/libsystem/dyld/coreFoundation(CF)
objc4-750源码 alloc 解析
证明 alloc确实是创建了对象
如何证明?
申请内存空间,有指针地址?
- 如果想证明上述所说,可以跑源码跟断点一步步查看。
通过源码分析,我们能看出在alloc的底层实现里面,alloc确实有申请内存空间创建对象。
alloc 创建对象跟踪
结论:
calloc,申请一片空间大小
initInstanceIsa: 关联class(isa)
- 不想断点一步步,也可以在libobjc.A.dylib 'objc_alloc' 汇编处直接查看寄存器状态,来证明
需要进行定点分析,找主线:
跳到断点到需要研究的地方:(确定研究对象)
通过简单的源码查看,我们可以依次加几个符号断点:
- 加符号断点+alloc
- 加符号断点+_objc_rootAlloc
- 加符号断点+callAlloc
- 加符号断点+class_createInstance
在汇编处查看寄存器状态:
x0在汇编里面是传递值的地方也是返回值得地方
截屏2019-12-24下午4.29.16.png
register read (读取寄存器)判断是否来到了我们需要的分析的方法
register read x0
刚进来x0还是TestPerson,没有返回地址
截屏2019-12-24下午4.32.23.png
结论:最后确实返回了地址,证明申请了内存空间,也就是创建了对象
0x003 源码详解:libobjc.A.dylib 'objc_alloc' (直接跑源码)
通过 0x2 读源码
可以知道alloc创建对象的核心:cls->instanceSize
;calloc
;initInstanceIsa
,现在来依次看看这几个方法
calloc开辟多少内存空间呢?
cls->instanceSize
计算对象需要的内存大小
计算size前
empty-object计算size前.png
内存对齐 [为什么要内存对齐]
内存对齐.png
计算size后
empty-object计算size后.png
calloc
:申请内存空间 & initInstanceIsa
:关联ISA
obj = (id)calloc(1, size);
if (!obj) return nil;
obj->initInstanceIsa(cls, hasCxxDtor);
系统创建一块内存地址并且与类关联起来。(相当于建了房子,要有一个房本将房子与房主关联起来。)
initInstanceIsa 详解
内存空间里面有些什么?(房子里面住谁?)
属性
下面有一个这样的对象,来看看对象内存地址里面分别存着什么
截屏2019-12-24下午6.24.56.png
打印地址
截屏2019-12-24下午6.05.23.png
结论:po 地址,验证地址与属性关系,可以验证,确实这些属性都会存放在对象开辟的内存地址空间内。只是属性地址分布的地址段会按照内存对齐的原则以及做一些优化,存放,具体请看内存对齐原则.
补充:也可以查看全部地址信息
截屏2019-12-24下午6.09.18.png
地址段
截屏2019-12-24下午6.10.41.png
0x004 最后说说init
从热身的打印结果看,其实alloc后就已经有创建了对象实例,init什么也没做.
那init意义何在:
工厂设计模式:预留,方便子类自定义重写
0x005 new
+ (id)new {
return [callAlloc(self, false/*checkNil*/) init];
}
alloc底层调用
id
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
callAlloc
// Call [cls alloc] or [cls allocWithZone:nil], with appropriate
// shortcutting optimizations.
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{....}
所以其实
[xxx new] == [[xxx alloc] init];
0x006 总结
- 定位 alloc 源码位置
- 粗略验证 alloc 创建对象
-
alloc
, 调用流程
_objc_rootAlloc
——>callAlloc
——>class_createInstance
——>_class_createInstanceFromZone
(cls->instanceSize
;(id)calloc(1, size)
;obj->initInstanceIsa(cls, hasCxxDtor)
;) - 分析内存大小计算逻辑
- init 和 new
网友评论