美文网首页iOS开发点滴
都别吵了,看了这篇iOS的OC中alloc执行原理,你什么都明白

都别吵了,看了这篇iOS的OC中alloc执行原理,你什么都明白

作者: 一眼万年的星空 | 来源:发表于2022-10-01 16:07 被阅读0次

    前言
    前面我们使用官方开源的objc源码进行了编译调试

    objc4-818.2源码编译调试笔记

    前言为什么会想要调试源码? 苹果开源了部分源码, 但相似内容太多, 基本找不到代码见的对应关系, 如果能像自己工程一样进行跳转那多好哇~~苹果源码开源地址: https://opensource.apple.com/本文将以macOS 11.2/objc4-818.2的源码进行配置源码配置首先...

    然后基于这份笔记, 开始探索OC的底层原理


    alloc源码探索
    众所周知, OC里"万物皆对象", 而这个对象则是通过alloc来创建的, 那么接下来我们就从这个点开始吧
    首先创建一个类"ABC"(里面空实现), 然后在main中写上如下代码, 并在alloc那行打上断点

    3555E00F556F934FFFB0EC6523


    按⌘+r运行一下, 停在断点位置以后按下

    按钮, 我们进去里面的代码看看 C102083A0F037E2D59491


    继续往里面走ing..

    3F1304E6C65C637B656224B67


    继续往里面走ing..

    7808B1A93D015650F947B05

    这里往下走ing.. (主要目的是先大概走完alloc的逻辑嘛~)

    7B7420239815E7D7D3B5E


    在fastpath()这个判断里面return了
    这个hasCustomAWZ()是判断 是否有自定义的+allocWithZone方法实现
    这里if是取反的, 所以是没有自定义的+allocWithZone方法就往if判断里面走
    而自定义的+allocWithZone方法里, 瞄了一眼, 实际也是调用_objc_rootAllocWithZone()函数
    我们继续往里走一下看看..

    411ADA1DCF94E21F0FEB44EFCFA


    继续往里面走ing..

    EB2AFE6598E9C18F1465D9


    先记录一下调这函数的传参

    cls Class ABC 0x00000001000080e8
    
    extraBytes size_t 0
    
    zone void * NULL 0x0000000000000000
    
    construct_flags int 2
    
    cxxConstruct bool true
    
    outAllocatedSize size_t* NULL 0x0000000000000000
    

    这里往下走看看..


    42245E9277B18A9992B103g


    可以看见, 这里是走calloc()的判断, 而这里的size是由instanceSize()计算得出的

    // 计算需要开辟的内存大小, 传入的extraBytes为0
    
    size = cls->instanceSize(extraBytes); //size=16
    

    calloc()方法给obj对象申请了一块内存空间
    继续往下走看看..

    BB576EF8F3554E806C3A24


    来到的是initInstanceIsa()的判断里面, 我偷偷瞄了一下里面在干啥(就简单概括了):

    initInstanceIsa() -> initIsa()
    
    // 这里的isa为objc_object结构体的私有变量, 大概意思就是--将isa和cls进行绑定
    
    -> { newisa.setClass(cls) + isa=newisa }
    

    回来继续往下走哈..


    7236D2BFA3A5D6466F06Cg


    走到这里就直接return一个obj对象了
    吓得我赶紧查了一下fastpath()这个宏函数

    #define fastpath(x) (__builtin_expect(bool(x), 1)) //x很可能为真
    
    #define slowpath(x) (__builtin_expect(bool(x), 0)) //x很可能为假
    

    附 __builtin_expect()的作用
    https://blog.csdn.net/qq_22660775/article/details/89028258
    作用是"允许程序员将最有可能执行的分支告诉编译器", 即
    __builtin_expect(EXP, N) 意思是:EXP==N的概率很大。

    附 instanceSize()的展开
    对alloc内计算大小的逻辑进行展开

    11E6E3988E4BE803B723D2932608


    fastpath()里面return了fastInstanceSize()方法, 其作用从名字上能知道: 快速计算内存大小

    E6FB99F2CDD48141A78D512EF030g


    展开后能通过断点发现, 它进行了16字节对齐

    2C3915F72165F0D223FB2g


    按照对齐公式
    假设: 传进去 x是10
    得到: (10 + 15) & ~15
    10+15=25 在二进制中表现为 0001 1001
    15 在二进制中表现为 0000 1111
    ~15 在二进制中表现为 1111 0000
    25 & ~15 在二进制中表现为 0001 0000 => 十进制中表现为 16
    好家伙! 不满16的直接对齐成16了
    引用百度上大佬的结论: (链接)
    ① 性能快 以空间换取时间
    ② 16字节对齐,使之有更大的容错空间
    ③ 会"属性重排", 进行内存优化

    总结
    到目前为止+alloc方法的底层逻辑如下:

    +[cls alloc] //从main中的alloc方法开始
    
    ↓
    
    _objc_rootAlloc()
    
    ↓
    
    callAlloc()
    
    ↓
    
    _objc_rootAllocWithZone()
    
    ↓
    
    _class_createInstanceFromZone()
    
    ↓ //===以下是内部实现逻辑===
    
    ↓ //从这里开始是核心内容了
    
    instanceSize() //计算需要开辟的内存空间大小
    
    ↓
    
    calloc() //申请开辟一块内存空间并返回地址指针
    
    ↓
    
    initInstanceIsa() //将isa和cls进行绑定
    
    ↓
    
    return obj //返回alloc好的obj对象
    
    ↓ //===这里走出内部实现逻辑了===
    
    ↓
    
    ABC *object //得到实例对象
    

    通过对alloc底层源码的分析, 可以了解到:
    ① alloc的主要目的是开辟内存空间;
    ② 主要的核心逻辑是 计算内存大小->申请内存空间->绑定isa;
    ③ 计算内存大小是按照16字节对齐的。


    init源码探索
    看完alloc源码, 总有点忍不住探索一下-init方法
    直接在上面的代码里稍作修改, 打上断点, 点击运行~~

    3555E00F556F934FFFB0EC65238E12E4.jpg


    迫不及待开始了

    C102083A0F037E2D59491CC883g


    进去看看..

    C9CA64CD099C65599722D11479g


    啊这... 就返回self了

    总结
    到目前为止-init方法的底层逻辑如下:

    - [obj init]
    
    ↓
    
    _objc_rootInit()
    
    ↓
    
    return obj
    

    通过对init底层源码的分析, 可以了解到:
    ① 它返回了自己.. 啥都没干


    new源码探索
    快速开始吧

    9FBF6DC1F54FF751D3E83pg


    走起!

    871FAE0CAB93AE4FE61819Ag


    总结
    到目前为止+new方法的底层逻辑如下:

    +new方法 = [callAlloc() init]
    

    通过对new底层源码的分析, 可以了解到:
    ① new = [[cls alloc] init]

    在以上源码中添加断点后,调试过程我总结成了一张图:\

    imagng

    文字流程:
    + alloc--_objc_rootAlloc--callAlloc--_objc_rootAllocWithZone--_class_createInstanceFromZone (核心实现,在方法中,完成对象大小计算,对齐,开辟,关联)

    总结:

    本文为oc对象的初步探究,仅提到oc对象alloc的流程,init过程将在下一章讲述。

    青山不改,绿水常流。谢谢大家!

    相关文章

      网友评论

        本文标题:都别吵了,看了这篇iOS的OC中alloc执行原理,你什么都明白

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