美文网首页
iOS alloc & init 探索

iOS alloc & init 探索

作者: 恬甜咖啡糖_0301 | 来源:发表于2019-12-25 18:28 被阅读0次

    0x000 从哪里入手?

    先看看main函数

    0x001 初探?

    1. 为什么是 alloc init?
    2. 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确实是创建了对象

    如何证明?
    申请内存空间,有指针地址?

    1. 如果想证明上述所说,可以跑源码跟断点一步步查看。
      通过源码分析,我们能看出在alloc的底层实现里面,alloc确实有申请内存空间创建对象。
    alloc 创建对象跟踪

    结论:
    calloc,申请一片空间大小
    initInstanceIsa: 关联class(isa)

    1. 不想断点一步步,也可以在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->instanceSizecallocinitInstanceIsa,现在来依次看看这几个方法

    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 总结

    1. 定位 alloc 源码位置
    2. 粗略验证 alloc 创建对象
    3. alloc, 调用流程
      _objc_rootAlloc ——> callAlloc ——> class_createInstance ——> _class_createInstanceFromZone(cls->instanceSize;(id)calloc(1, size);obj->initInstanceIsa(cls, hasCxxDtor);)
    4. 分析内存大小计算逻辑
    5. init 和 new

    相关文章

      网友评论

          本文标题:iOS alloc & init 探索

          本文链接:https://www.haomeiwen.com/subject/ljwmnctx.html