iOS底层原理:OC对象底层探索之alloc初探(二)

简介: 简介: iOS开发的小伙伴们对 [XXX alloc] init] 都不陌生,可以说 alloc 和 init 贯穿我们整个的开发过程中。那么在OC对象的底层,到底做了哪些操作呢?今天我们就来探索一下 alloc 底层的工作流程。
第2步:llvm-project 底层分析

由于 llvm-project 项目比较大,这里我们用 VSCode 打开

  1. 首先,我们全局搜索一下alloc或者OMF_alloc:,来到tryGenerateSpecializedMessageSend方法,这个方法在 CGObjC.cpp 文件中



image.png


21-1.png

我们主要看3号位置的方法解释,这里我翻译了一下,大家可以自行去看,这是苹果对性能的一个优化。主要意思就是:objc在运行时提供了快捷入口,这些入口比普通的消息发送速度更快,如果运行支持所需要的入口的话,这个方法就会调用并返回结果,否则返回None,调用者自己生成一个消息发送。

  1. 知道了tryGenerateSpecializedMessageSend的作用,接着我再来看一下tryGenerateSpecializedMessageSend方法的调用情况,搜索tryGenerateSpecializedMessageSend,来到GeneratePossiblySpecializedMessageSend


image.png

这个方法是运行时在底层的入口,所有的消息发送都会走这里。从代码可以看出,如果tryGenerateSpecializedMessageSend方法返回None,这里判断为false,就会走GenerateMessageSend方法,也就是调用者自己生成一个普通的msgSend

  1. 然后,我们深入到tryGenerateSpecializedMessageSend方法中,看看alloc是怎么被执行成了objc_alloc。这里看一下tryGenerateSpecializedMessageSend方法中4号位置的代码,这里有个条件判断 if (Sel.isUnarySelector() && Sel.getNameForSlot(0) == "alloc") ,如果成立,就会走EmitObjCAlloc方法,搜索一下,进去看一下


image.png


可以看到EmitObjCAlloc方法这里生成了一个objc_alloc的入口(ObjCEntrypoints),包装为emitObjCValueOperation被返回执行,并且llvm对此做一个标记存在Selector中,而Selector则记录在SelectorTable


image.png


image.png


image.png

image.png


由此可以验证:[JQPerson alloc]在底层会先走到objc_alloc

  1. objc_alloc第一次调用callAlloc方法,会执行msgSend(cls, @selector(alloc))(ps:这个第3步 callAlloc中会讲,这里知道一下,先把llvm这个流程讲完)。
    此时llvm底层还是会走tryGenerateSpecializedMessageSend,此时,由于已经标记了allocSelector,不会再走if (Sel.isUnarySelector() && Sel.getNameForSlot(0) == "alloc")这个判断中的代码,最终返回None。然后由GenerateMessageSend走普通的消息发送。


第3步:callAlloc

好了,allocobjc_alloc的调用清晰了。接着,我们来看一下最核心的方法callAlloc

  1. objc 源码中我们可以看到objc_alloc方法中调用了callAlloc


image.png

我们观察一下callAlloc中的代码,会发现这个方法的最后一行(1937行)对传入的 cls 做了一次消息发送,发送的消息名称正是alloc,这似乎可以解释上面走完objc_alloc方法后,又走到alloc的现象。但是我们还需要打断点,走一下流程来验证。


image.png

  1. 经断点调试,执行objc_alloc后,callAlloc确实走到了发送alloc消息这一行,也就是[JQPerson alloc] => objc_alloc => callAlloc

image.png

继续走断点,我们会发现执行流程为:[JQPerson alloc] => objc_alloc => callAlloc => alloc => _objc_rootAlloc => callAlloc =>_objc_rootAllocWithZone


image.png

  1. 当前我们已经走完了 main.m 中的16行,也就是(JQPerson)p1alloc,此时断点会来到17行(JQPerson)p2alloc
  2. 继续走源码断点,会发现执行流程为:[JQPerson alloc] => objc_alloc => callAlloc => _objc_rootAllocWithZone

image.png

image.png

29.png

这里我们就会奇怪,为什么JQPerson类再次alloc时,就直接走到if (fastpath(!cls->ISA()->hasCustomAWZ()))条件判断中的代码了呢?

  1. 那我们就来看一下if (fastpath(!cls->ISA()->hasCustomAWZ()))这句判断到底执行了什么?
    进入到if (fastpath(!cls->ISA()->hasCustomAWZ()))源码中看一下


image.png

image.png

由以上源码可以看出:

a.  当JQPerson类第一次调用alloc方法时,底层会先调用objc_alloc,此时callAlloc被第一次调用,callAlloc内部通过当前clsISA返回一个Class对象;

b. 紧接着会去判断当前ClasscacheFAST_CACHE_HAS_DEFAULT_AWZ(存储在元类metaclass中,记录着cache中是否已经缓存了alloc/allocWithZone:方法的实现)这个标志位的值是否为真,由于是第一次执行,没有缓存,所以cache.getBit(FAST_CACHE_HAS_DEFAULT_AWZ)取出来的值是false,前面加个,变成了truecallAllocif (fastpath(!cls->ISA()->hasCustomAWZ()))又加了个,所以值为false

c. 然后走到了if (allocWithZone),由于objc_alloc方法中allocWithZone参数传值为false,所以走到了(objc_msgSend)(cls, @selector(alloc))。然后,callAlloc被第二次调用,由于执行过了alloc方法,所以此时有了alloc的方法缓存,所以if (fastpath(!cls->ISA()->hasCustomAWZ()))判断为true,执行_objc_rootAllocWithZone

d. 最后就是 main.m 中第17行JQPerson类第二次调用alloc方法,此时由于JQPerson类的cache中已经有了缓存,FAST_CACHE_HAS_DEFAULT_AWZ这个标志位的值为真,也就是if (fastpath(!cls->ISA()->hasCustomAWZ()))这个条件为真,所以,会直接执行_objc_rootAllocWithZone

下面我画一下流程图,帮助小伙们理解一下:

image.png

[JQPerson alloc]流程图新.png

另外,这里我附一张NSObject alloc]的流程图,有兴趣的小伙们可以去试一试:


image.png

这里NSObject alloc]只走了一遍callAlloc方法,猜测原因是:系统对 NSObject 做了优化,提前给cache添加了缓存。

好了,alloc的底层探索今天先写到这里。下面一篇文章我们将探索一下alloc开辟内存空间相关的源码。敬请期待吧!!!


相关文章
|
6月前
|
存储 运维 安全
iOS加固原理与常见措施:保护移动应用程序安全的利器
iOS加固原理与常见措施:保护移动应用程序安全的利器
89 0
|
6月前
|
存储 运维 安全
iOS加固原理与常见措施:保护移动应用程序安全的利器
iOS加固原理与常见措施:保护移动应用程序安全的利器
141 0
|
C语言 索引
09-iOS之load和initialize底层调用原理分析
09-iOS之load和initialize底层调用原理分析
88 0
|
6月前
|
安全 前端开发 数据安全/隐私保护
【教程】 iOS混淆加固原理篇
本文介绍了iOS应用程序混淆加固的缘由,编译过程以及常见的加固类型和逆向工具。详细讨论了字符串混淆、类名、方法名混淆、程序结构混淆加密等加固类型,并介绍了常见的逆向工具和代码虚拟化技术。
|
6月前
|
安全 算法 前端开发
【完整版教程】iOS混淆加固原理篇
在iOS开发中,应用程序的安全性和保护显得尤为重要。由于iOS系统的开放性,一些逆向工具可以轻松地对应用程序进行反编译和分析,从而导致应用程序源代码、算法和敏感信息的泄露。为了保护应用程序的安全性,我们需要对应用程序进行混淆加固。本文将介绍iOS混淆加固的原理和常见的加固类型。
|
6月前
|
JSON 安全 数据安全/隐私保护
​iOS Class Guard github用法、工作原理和安装详解及使用经验总结
​iOS Class Guard github用法、工作原理和安装详解及使用经验总结
97 0
|
6月前
|
安全 数据安全/隐私保护 iOS开发
【iOS开发】iOS App的加固保护原理:使用ipaguard混淆加固
【iOS开发】iOS App的加固保护原理:使用ipaguard混淆加固
87 0
|
运维 安全 数据安全/隐私保护
iOS加固原理与常见措施:保护移动应用程序安全的利器
随着移动应用的普及和用户对数据安全的关注度提高,iOS加固成为了很多开发者和企业的必备工具。那么,iOS加固是如何保护应用程序的安全性的呢? iOS加固是指对OS应用程序进行一系列的安全措施,以提高其抗逆向工程、反编译和破解的能力。下面将介绍iOS加固的原理和常见的加固措施。
iOS加固原理与常见措施:保护移动应用程序安全的利器
|
11月前
|
JSON 安全 数据安全/隐私保护
​iOS Class Guard github用法、工作原理和安装详解及使用经验总结
iOS Class Guard是一个用于OC类、协议、属性和方法名混淆的命令行工具。它是class-dump的扩展。这个工具会生成一个symbol table,这个table在编译期间会包含进工程中。iOS-Class-Guard能有效的隐藏绝大多数的类、协议、方法、属性和 实例变量 名。iOS-Class-Guard不是应用安全的最终解决方案,但是它绝对能让攻击者更难读懂你的程序。iOS-Class-Guard会加大代码分析和runtime检查的难度,这个工具可以认为是一个简单基础的混淆方法。由于OC的架构决定了iOS应用程序的剖析相当简单,check out一下链接就知晓了:
|
安全 数据安全/隐私保护 iOS开发
【iOS开发】iOS App的加固保护原理:使用ipaguard混淆加固 摘要
随着智能手机的普及,越来越多的用户使用iOS设备来处理日常任务,因此iOS应用程序的安全性变得越来越重要。为了防止应用程序被攻击或破解,开发人员需要采用一些保护措施来加固应用程序。本文将介绍一种使用ipaguard混淆加固的方法来保护iOS应用的安全。