优化 Objective-C runtime(wwdc2020)
wwdc2020上,苹果对oc的runtime的3个部分优化做了介绍
1.类数据结构变化
2.方法偏移列表
3.tagged pointers
1.类数据结构变化
Clean memory
指的是加载后不会发生变化的内存,是一个应用常驻内存的只读内存页集,iOS能够安全地从磁盘中移除或重载 class_ro_t
这部分内存空间
Dirty memory
指的是无法被系统主动移除的常驻内存部分,运行过程中,可能会发生变化的内存class_rw_t
这部分内存空间
Dirty memory
比较昂贵,一旦加载进来就不能释放
Clean memory
可以进行移除,需要时再重新载入内存
由于各自的特性拆分出两种内存结构,所以可以看出,尽量把不改变的类结构放到Clean memory
有助于提高性能
经过调查,在iphone运行时,大约会有30mb的class_rw_t
的内存结构空间,
但其实只有10%的类会用到动态添方法等
所以我们针对这部分做优化,预计可以节约14mb的内存空间
把可能动态变化的结构,放到class_rw_ext_t
结构里,在需要的时候创建,
如果你的代码自行调用了class_rw_t
,在这次更新后,可能会出现异常,
建议使用官方的Api进行访问,是安全的
class_getName
class_getSuperclass
class_copyMethodList
2.方法列表偏移
方法列表包含三个部分,selector
imp
和方法编码,在64位系统中,每个部分占用8个字节
加起来一个方法列表共占用24字节,class_ro_t
是clean memory
由于image内部的地址是连续的,寻址的过程中不需要64位的寻址空间,完全可以只用32位的偏移地址+image的地址就可以正常访问
经过验证methods占用的内存空间常驻大约是80mb,经过此方法优化可以节约40mb可观的空间
方法交换(Method swizzling)怎么办?
由于优化后method list
无法获取完整的方法地址,但如果你想交换方法实现,仍可以继续使用
通过创建一个全局mappling table
,来存储需要交换的方法
相应的swizzling method
得效率会有所降低,但实际上swizzling method
使用的场景有限,这个全局表不会太大,效率也不会降低太多
还有一个优点,相比于原有method list
结构,被”dirtied”的内存仅有全局的这个Mapping table
这些变化都是无感的,不影响现有代码
新的方法偏移列表优化在macOS Big Sur
ios 14
等新版系统实现
当然也会兼容旧版本
如果在旧版本OS运行,按照对象读取会把methods
的2个4字节偏移量按照一个8字节的全局地址处理,会造成异常,所以要使用APIs
method_getName
method_getTypeEncoding
method_getImplementation
3.Tagged pointers
tagged pointers
是经过混淆的,很难被伪造
从右至左,
第1位 1
代表Tagged pointers
,0
代表对象指针
第2-4位 Tag
表示对象类型 3
代表NSNumber等
剩下位的是payload
如果Tag
位是7,会用第5-12位作为扩展使用
就可以额外有256个标签类型,可以扩展更多的类型
要注意的是和intel架构不同,arm64是指针是反过来的,
这样就可以一次判断就确定是tagged
或者nil
,避免分开判断,节省了条件分支
1 | if (ptr <= 0)//tagged or nil |
今年做了优化,把Tag
放到了低位
ios14之后的有些处理指针位信息的会产生预料之外的问题
使用APIs
处理
例如
1 | if ([obj isKindOfClass:[NSString class]]) {} |