本文以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究竟都干了什么呢,底层都触发哪些方法?这是我们要研究的,下面是探究源码的三种方式:
三种探究底层调用的方式
- 断点+controlStep into
 断点+control stepinto1.jpg
 断点+control stepinto2.jpg
 
- 断点+
- 符号断点定位查流程
 我们现在知道alloc会执行objc_alloc,那我们可以增加符号断点,看一下下面的流程是什么
 符号断点步骤1.png
 符号断点步骤2.png
 
- 符号断点定位查流程
下面就是运行项目,此处要注意的是先把objc_alloc断点关闭,程序启动会加载预处理的很多类,为了方便我们调试自己的类alloc情况,我们走到创建类的alloc断点时,把objc_alloc断点打开,下一步

符号断点步骤3.png
- Debug汇编查看流程
 汇编查看流程调试1.png
 汇编查看流程调试2.png
 下面可以继续control+step into
 汇编查看流程调试3.png
 
- Debug汇编查看流程
现在我们知道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
 我们看到这里先返回当前类的ISA的Class对象,判断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 内的关键方法 ,这里主要有三个步骤:
- 
size = cls->instanceSize(extraBytes);计算类需要开辟的内存空间大小
- 
obj = (id)calloc(1, size);申请开辟内存空间
- 
obj->initInstanceIsa(cls, hasCxxDtor);将类cls和obj指针进行关联
到此时,alloc整个流程执行完毕
总结
alloc流程图如下

alloc流程









