iOS开发底层之alloc原理初探

Posted iOS_developer_zhong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS开发底层之alloc原理初探相关的知识,希望对你有一定的参考价值。

第一部分 源码探索之如何找到对应的源码位置?

如: 我想探寻代码中 某个类的 alloc 内部实现。 则三种实现方式如下:

  • (方式一)通过符号断点与在需要探寻的代码处打断点。 (不常用)

1. 步骤实现

2. 在执行到zrgObject 断点后, 继续往下运行,就可以alloc的源码位于哪个位置。 

  • (方式二)通过断点与调试功能(进入内部) + 符号断点 。 (常用)

1.步骤如下

2:第二步的时候,是按住ctrl键,然后按进入下一步,就会出现如下界面

 

3: 继续执行,就可以看到源码到底在哪个位置了

  • (方式三) 直接改变xcode配置,直接展示汇编

1:设置步骤  Debug -> debug workflow ->  always Show Disassembly

2.  通过按住 ctrl 键 + 跳入内部按钮 截图展示如下:

3. 完成上述步骤后,直接继续运行,就大功告成了,知道了源码的所属位置。 

第二部分 objc源码编译调试

既然我们要分析objc源码,所以需要下载objc源码, 由于我的xcode是12.3所以找了个

xcode12以上版本可以跑的源码 objc4-818.2

苹果的官方源码下载链接地址: 源码下载地址

下载完毕后,需要自己去做配置,过程比较繁琐,后期常识自己做编译调试。 

第三部分 alloc init、new 的关联与区别

1. 有的上面的 objc源码,我们直接看源码

// alloc  _objc_rootAlloc
id _objc_rootAlloc(Class cls)
{
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}


// init 

+ (id)init {
    return (id)self;
}


// new 
+ (id)new {
    return [callAlloc(self, false/*checkNil*/) init];
}

结论:

通过上面的代码我们清晰的看到alloc init , 和new的作用是一样的, 分配内存完成初始化。 

但new使用的是默认初始化, 通常我们使用alloc init,是因为可以自定义初始化对象。 

第四部分 NSObject的alloc 源码分析

深入探索 alloc,到底经过了哪些步骤。 

方法的顺序为:

alloc --> _objc_rootAlloc --> callAlloc --> _objc_rootAllocWithZone --> _class_createInstanceFromZone

分析 :  _class_createInstanceFromZone 方法

1. 分析计算所需要的内存源码

// 计算内存大小
    inline size_t instanceSize(size_t extraBytes) const {
        if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
            return cache.fastInstanceSize(extraBytes);
        }

        size_t size = alignedInstanceSize() + extraBytes;
        // CF requires all objects be at least 16 bytes.
        if (size < 16) size = 16;
        return size;
    }


//   十六进制 字节对齐
    size_t fastInstanceSize(size_t extra) const
    {
        ASSERT(hasFastInstanceSize(extra));

        if (__builtin_constant_p(extra) && extra == 0) {
            return _flags & FAST_CACHE_ALLOC_MASK16;
        } else {
            size_t size = _flags & FAST_CACHE_ALLOC_MASK;
            // remove the FAST_CACHE_ALLOC_DELTA16 that was added
            // by setFastInstanceSize
            return align16(size + extra - FAST_CACHE_ALLOC_DELTA16);
        }
    }

// 具体算法  如: (8 + 15) & (15取反)
static inline size_t align16(size_t x) {
    return (x + size_t(15)) & ~size_t(15);
}

核心为: 新的苹果编译器是 16字节对齐, 算法为16的倍数 。 

为什么要16字节对齐?

      苹果以前是8字节对齐, 后面改成16字节对齐,以前的是8字节在内存中的存放,会一个紧挨着一个,会出现内存访问错误, 野指针。  在oc中,一个对象为八个字节, 为了统一化,为了提高内存的读写速度, 不会因为对象的大小不同,而改变读取的长度, 所以固定为字节整段长度为8的倍数。 16字节会更加安全与快捷。 

2。 分析开辟内存的源码:

alloc的核心逻辑就从 calloc入手,下面介绍,进入这个方法的流程。 

为了探索这个方法,需要下载另外一份源码 libmalloc源码

接下来详细流程,后空再更新。 
 

 

 

以上是关于iOS开发底层之alloc原理初探的主要内容,如果未能解决你的问题,请参考以下文章

iOS 底层原理之alloc探究

iOS 底层原理之alloc探究

iOS开发底层之NSObject-alloc源码分析-02

iOS开发之alloc底层探索之旅

iOS开发底层之内存对齐详解-03

iOS 底层原理 + 逆向 文章汇总