IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> iOS底层-alloc (1) -> 正文阅读

[移动开发]iOS底层-alloc (1)


?

写在前面: iOS底层原理探究是本人在平时的开发和学习中不断积累的一段进阶之
路的。 记录我的不断探索之旅,希望能有帮助到各位读者朋友。

内容的总结专栏


作为一名iOS开发人员,在平时开发工作中,所有的对象我们使用最多的是alloc来创建。那么alloc底层做了哪些操作呢?接下来我会一步一步探究alloc方法的底层实现。

初探

我们先来看下面的代码

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

打印内容:

    <SMPerson: 0x600000710400>-0x600000710400-0x7ffee6f15088
    <SMPerson: 0x600000710400>-0x600000710400-0x7ffee6f15080
    <SMPerson: 0x600000710400>-0x600000710400-0x7ffee6f15078

可见,在?SMPerson?使用?alloc?方法从系统中申请开辟内存空间后?init方法并没有对内存空间做任何的处理,地址指针的创建来自于?alloc方法。如下所示:

f3b265afd6f74aad8294ee5aaef6c439~tplv-k3u1fbpfcp-watermark.image

注:细心的你一定注意到了,p1、p2、p3都是相差了8个字节。 这是因为,指针占内存空间大小为8字节,p1、p2、p3 都是从栈内存空间上申请的,且栈内存空间是连续的。同时,他们都指向了同一个内存地址。

那么,?alloc?是如何开辟内存空间的呢?

首先,第一反应是,我们要Jump to Definition,

99ab465148cd4dfcb1b98075a74897ef~tplv-k3u1fbpfcp-watermark.image

结果,Xcode中并不能直接跳转后显示其底层实现,所以 并不是我们想要的。

e75dfdfd5bdc4f34992a3271ce022b04~tplv-k3u1fbpfcp-watermark.image

058f57da0130439389bd3d0aaf1d0bd7~tplv-k3u1fbpfcp-watermark.image

中探

接下来,我们通过三种方法来一探究竟:

方法1

既然不可以直接跳转到API文档来查看alloc的内部实现,那么我们还可以通过下 符号断点 来探寻 其实现原理。

b3229ca82354493eb5d4da23b40bc42e~tplv-k3u1fbpfcp-watermark.image

接下来我们就来到此处

420df26edf014aec94507e3f8a102454~tplv-k3u1fbpfcp-watermark.image

一个名为 libobjc.A.dylib 的库,至此,我们就应该要去找苹果开源的库,以寻找我们想要的答案。

点击查看苹果开源源码汇总

方法2

我们也可以直接在alloc那一行打一个断点,代码运行到此处后,按住control键 点击 step into, 接下来,就来到里这里

0ced24e2146d48378224f837ecacacbf~tplv-k3u1fbpfcp-watermark.image我们可以看到一个 objc_alloc 的函数方法到调用,此时,我们再下一个符号断点,同样的,我们还是找到了 libobjc.A.dylib 这个库。

5d7c449423b4457394622eb39f0f6f43~tplv-k3u1fbpfcp-watermark.image

方法3

此外,我们还是可以通过汇编来调试和查找相应的实现内容,断点依然是在alloc那一行。

Debug > Debug Workflow > Always Show Disassembly

0268770539a34c978ca299408ce72f6f~tplv-k3u1fbpfcp-watermark.image

找到 callq 方法调用那一行,109dc2b91e26451183405de57c281c3c~tplv-k3u1fbpfcp-watermark.image

接着, step into 进去, 我们找到了 objc_alloc 的调用, 之后的操作和 方法2的后续步骤一样,最终,可以找到 libobjc.A.dylib 这个库。88eb55a992324f8b9a4d9626d6449fa2~tplv-k3u1fbpfcp-watermark.image

深探

下载源码??objc4-818.2

接下来对源码进行分析,

alloc方法会调用到此处

b212cb1230ad4cffae02ffa4f07f3516~tplv-k3u1fbpfcp-watermark.image

接着是 调用?_objc_rootAlloc

c54f6c3364014ecf9cd98fe6a0855c17~tplv-k3u1fbpfcp-watermark.image

之后调用 到?callAlloc

a3ddf7d3fc804e6bbc67b6e3fca89fd6~tplv-k3u1fbpfcp-watermark.image

跟着断点会来到?_objc_rootAllocWithZone

85d27e7f98eb4f17aeaed0a4c316c54d~tplv-k3u1fbpfcp-watermark.image

之后是?_class_createInstanceFromZone

此方法是重点

8c8928c08f454ecba4d912d989a8513d~tplv-k3u1fbpfcp-watermark.image

_class_createInstanceFromZone?方法中,该方法就是一个类初始化所走的流程,重点的地方有三处

第一处是:

    // 计算出开辟内存空间大小
    size = cls->instanceSize(extraBytes);

内部实现如下:?04a9c36635094b72ad667f2f7a94ffa4~tplv-k3u1fbpfcp-watermark.image其中在计算内存空间大小时,会调用?cache.fastInstanceSize(extraBytes)?方法,

最终会调用?align16(size + extra - FAST_CACHE_ALLOC_DELTA16)?方法。 align16 的实现如下:

static inline size_t align16(size_t x) {
    return (x + size_t(15)) & ~size_t(15);
}

可见, 系统会进行 16字节 的对齐操作,也就是说,一个对象所占用的内存大小至少是16字节。

在这里 我们举个例子: size_t x = 8; 那么 align16操作后的大小计算过程如下:

    (8 + 15) & ~15;
    
    0000 0000 0000 1000     8
    0000 0000 0000 1111     15  
    
=   0000 0000 0001 0111     23
    1111 1111 1111 0000     ~15
    
=   0000 0000 0001 0000     16

第二处是:

    ///向系统申请开辟内存空间,返回地址指针;
    obj = (id)calloc(1, size);

第三处是:

    /// 将类和指针做绑定
    obj->initInstanceIsa(cls, hasCxxDtor);

总结:

所以,最后我们总结一下, alloc的底层调用流程如下:

3939ad7d0f99434daa6d7a32f818f0f7~tplv-k3u1fbpfcp-watermark.image

就是这样一个流程,系统就帮我们创建出来一个类对象。

补充

d171a1a1529c49f5b59f0aca928d99e6~tplv-k3u1fbpfcp-watermark.image?

  • lldb 如何打印实力对象中成员为 double 类型的数值: e -f f -- <值>
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-09-15 02:07:57  更:2022-09-15 02:08:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 5:32:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码