OC对象原理探索(上)-alloc流程

本文以OC类创建的时候alloc具体都做了什么操作为出发点,去挖掘底层类创建的具体步骤

类创建alloc 时堆栈操作

首先,我们创建一个工程,新建一个类,名字随便起,我这边是LMPerson,下面是具体代码:

    LMPerson *p = [LMPerson alloc];
    LMPerson *p1 = [p init];
    LMPerson *p2 = [p init];
    NSLog(@"%@-%p-%p",p,p,&p);
    NSLog(@"%@-%p-%p",p1,p1,&p1);
    NSLog(@"%@-%p-%p",p2,p2,&p2);

运行程序,查看控制台打印信息:

<LMPerson: 0x6000027041e0>-0x6000027041e0-0x7ffee06f3208
<LMPerson: 0x6000027041e0>-0x6000027041e0-0x7ffee06f3200
<LMPerson: 0x6000027041e0>-0x6000027041e0-0x7ffee06f31f8

从打印信息,我们可以看出 alloc 的时候开辟了一个内存,init并没有对内存空间做任何操作, p,p1,p2的内存地址相同,指针地址不同。
可以用下面的图简单表示:

Snip20210609_5.png

alloc究竟都干了什么呢,底层都触发哪些方法?这是我们要研究的,下面是探究源码的三种方式:

三种探究底层调用的方式

    1. 断点+control Step into
      断点+control stepinto1.jpg

      断点+control stepinto2.jpg
    1. 符号断点定位查流程
      我们现在知道alloc会执行 objc_alloc,那我们可以增加符号断点,看一下下面的流程是什么
      符号断点步骤1.png

      符号断点步骤2.png

下面就是运行项目,此处要注意的是先把objc_alloc断点关闭,程序启动会加载预处理的很多类,为了方便我们调试自己的类alloc情况,我们走到创建类的alloc断点时,把objc_alloc断点打开,下一步

符号断点步骤3.png

    1. Debug汇编查看流程
      汇编查看流程调试1.png

      汇编查看流程调试2.png

      下面可以继续 control+step into
      汇编查看流程调试3.png

现在我们知道alloc底层会调用objc_alloc,那怎么看objc_alloc 后面的流程呢,这时候需要我们去查看苹果的源码
objc4-818.2.tar.gz,当前是这个源码,这个源码是不断更新的,查看最新的就可以
我们可以编译这个源码去查看底层实现,编译过程有很多问题需要处理,可以从网上找资料解决,也可以从github上下载别人编译好的来调试 ,比如 Cooci老师的github
ps:后面自己研究下怎么调试通源码

源码调试分析--alloc流程

我们把源码跑起来,一步步根据alloc的源码往里走

alloc源码1.png

alloc源码2.png

alloc源码3.png

这里__OBJC2__这个关键词就是判断objc的版本的,我们使用的最新版本,所以是会进入这里。
此处还有两个宏定义 :

  • slowpath:告诉编译器,传入的条件结果为假的可能性很大
  • fastpath:告诉编译器,传入的条件结果为真的可能性很大
    我们一步步step into 会发现走到了 fastpath里面,此处有一个判断 !cls->ISA()->hasCustomAWZ()
    1623808971265.jpg

    cache里是否有缓存.png

    我们看到这里先返回当前类的ISAClass对象,判断cache中有没有缓存,有->_objc_rootAllocWithZone,无->objc_msgSend,往下执行走到了_objc_rootAllocWithZone
    _objc_rootAllocWithZone.png

_objc_rootAllocWithZone调用了_class_createInstanceFromZone

static ALWAYS_INLINE id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
                              int construct_flags = OBJECT_CONSTRUCT_NONE,
                              bool cxxConstruct = true,
                              size_t *outAllocatedSize = nil)
{
    ASSERT(cls->isRealized());

    // Read class's info bits all at once for performance
    bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();
    bool hasCxxDtor = cls->hasCxxDtor();
    bool fast = cls->canAllocNonpointer();
    size_t size;

    size = cls->instanceSize(extraBytes);
    if (outAllocatedSize) *outAllocatedSize = size;

    id obj;
    if (zone) {
        obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
    } else {
        obj = (id)calloc(1, size);
    }
    if (slowpath(!obj)) {
        if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
            return _objc_callBadAllocHandler(cls);
        }
        return nil;
    }

    if (!zone && fast) {
        obj->initInstanceIsa(cls, hasCxxDtor);
    } else {
        // Use raw pointer isa on the assumption that they might be
        // doing something weird with the zone or RR.
        obj->initIsa(cls);
    }

    if (fastpath(!hasCxxCtor)) {
        return obj;
    }

    construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE;
    return object_cxxConstructFromClass(obj, cls, construct_flags);
}

这个是alloc 内的关键方法 ,这里主要有三个步骤:

  1. size = cls->instanceSize(extraBytes); 计算类需要开辟的内存空间大小
  2. obj = (id)calloc(1, size); 申请开辟内存空间
  3. obj->initInstanceIsa(cls, hasCxxDtor); 将类cls和obj指针进行关联

到此时,alloc整个流程执行完毕

总结

alloc流程图如下

alloc流程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335