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原理初探的主要内容,如果未能解决你的问题,请参考以下文章