Objective-C 是一门古老的语言,诞生于 1984 年,跟随 Apple 一路浮沉,见证了乔布斯创建了 NeXT,也见证了乔布斯重回 Apple 重创辉煌,它用它特立独行的语法,堆砌了 UIKit,AppKit, Foundation 等一个个基石,时间来到 2020 年,面对汹涌的"后浪" Swift,"老前辈" Objective-C 也在发挥着自己的余热,即使面对越来越多阵地失守,唯有“老兵不死,只会慢慢凋亡"才能体现的悲壮。今年,Apple 给 Objective-C Runtime 带来了新的优化,接下来,让我们深入理解这些变化。
首先我们先来了解一下二进制类在磁盘中的表示
首先是类对象本身,包含最常访问的信息:指向元类,超类和方法缓存的指针,在类结构之中有指向包含更多数据的结构体class_ro_t
的指针,包含了类的名称,方法,协议,实例变量等等编译期确定的信息。其中 ro 表示 read only 的意思。
当类被 Runtime 加载之后,类的结构会发生一些变化,在了解这些变化之前,我们需要知道2个概念:
Clean Memory:加载后不会发生更改的内存块,class_ro_t
属于Clean Memory
,因为它是只读的。
Dirty Memory:运行时会进行更改的内存块,类一旦被加载,就会变成Dirty Memory
,例如,我们可以在 Runtime 给类动态的添加方法。
这里要明确,Dirty Memory
比Clean Memory
要昂贵得多。因为它需要更多的内存信息,并且只要进程正在运行,就必须保留它。对于我们来说,越多的Clean Memory
显然是更好的,因为它可以节约更多的内存。我们可以通过分离出永不更改的数据部分,将大多数类数据保留为Clean Memory
,如何怎么做的呢?
在介绍优化方法之前,我们先来看一下,在类加载之后,类的结构会变成如何呢?
在类加载到 Runtime 中后会被分配用于读取/写入数据的结构体class_rw_t
。
Tips:
class_ro_t
是只读的,存放的是编译期间就确定的字段信息;而class_rw_t
是在 runtime 时才创建的,它会先将class_ro_t
的内容拷贝一份,再将类的分类的属性、方法、协议等信息添加进去,之所以要这么设计是因为 Objective-C 是动态语言,你可以在运行时更改它们方法,属性等,并且分类可以在不改变类设计的前提下,将新方法添加到类中。
事实证明,class_rw_t
会占用比class_ro_t
占用更多的内存,在 iPhone 中,我们在系统测量了大约 30MB 的这些class_rw_t
结构。应该如何优化这些内存呢?通过测量实际设备上的使用情况,我们发现大约 10% 的类实际会存在动态的更改行为,如动态添加方法,使用 Category 方法等。因此,我们能可以把这部分动态的部分提取出来,我们称之为class_rw_ext_t
,所以,结构会变成这个样子。
经过拆分,可以把 90% 的类优化为Clean Memory
,在系统层面,取得效果是节省了大约 14MB 的内存,使内存可用于更有效的用途。
Tips:
head xxxxx | egrep 'class_rw|COUNT’
你可以使用此命令来查看class_rw_t
消耗的内存。xxxx可以替换为需要测量的 App 名称。如:head Mail | egrep 'class_rw|COUNT’\'
查看 Mail 应用的使用情况。
现在,我们来看看 Runtime 的第二处的变化,方法地址的优化。
每个类都包含一个方法列表,以便 Runtime 可以查找和消息发送。结构大概如下图所示:
方法包含了3部分的内容:
在 64 位系统中,它们占用了 24 字节的空间
了解了方法的结构之后,我们来看下进程中内存的简化视图
这是一个 64 位的地址空间,其中各种块分别表示了栈,堆以及各种库。我们把焦点放在 AppKit 库中的init
方法。
如图所示,图中的3个地址分别为方法的 3 个部分的表示的绝对地址,我们知道,库的地址取决于动态链接库加载之后的位置,ASLR(Address space layout randomization 地址空间布局随机化)的存在,动态链接器需要修正真实的指针地址,这也是一种代价。由于方法实现地址不会脱离当前库的地址范围的特性存在,所以实际上,方法列表并不需要使用 64 位的寻址范围空间。他们只需要能够在自己的库地址中查找引用函数地址即可,这些函数将始终在附近。所以我们可以使用 32 位相对偏移来代替绝对 64 位地址。
现在我们地址将变成这样
这么做有几个优点:
优化后,指针所需的内存占用量可以减少一半。
相对方法地址会引发另外一个问题,那就是在Method Swizzling
如何处理呢?众所皆知,Method Swizzling
替换的是 2 个方法函数指针指向,方法函数实现可以在任意地方实现,使用了相对偏移地址了之后,这样就无法工作了。
针对Method Swizzling
我们使用全局映射表来解决这个问题,在映射表中维护Swizzles
方法对应的实现函数指针地址。由于Method Swizzling
的操作并不常见,所以这个表不会变得很大,新的Method Swizzling
机制如下图。
接下来我们会深入了解 Tagged Pointer 在 ARM CPU 下的格式变化 首先,让我们先来了解下 Tagged Pointer 是什么 Tagged Pointer:一种特殊标记的对象,Tagged Pointer 通过在其最后一个 bit 位设置为特殊标记位,并且把数据直接保存在指针本身中。Tagged Pointer 是一个"伪"对象,使用 Tagged Pointer 有 3 倍的访问速度提升,100 倍的创建、销毁速度提升。
Tips:Advances in Objective-C
在我们查看对象指针时,在 64 位系统中,我们会看到 16 进制地址如0x00000001003041e0
,我们把它转换为二进制表示如下图
在 64 位系统中,我们有 64 位可以表示一个对象指针,但是我们通常没有真正使用到所有这些位,由于内存对齐要求的存在,低位始终为0,对象必须始终位于指针大小倍数的地址中。高位也始终为0。实际上我们只是用中间这一部分的位。
因此,我们可以把最低位设置为 1,表示这个对象是一个 Tagged Pointer 对象。设置为 0 则表示为正常的对象
在设置为 1 表示为 Tagged Pointer 对象之后,在最低位之后的 3 位,我们给他赋予类型意义,由于只有 3 位,所以它可以表示 7 种数据类型
OBJC_TAG_NSAtom = 0,
OBJC_TAG_1 = 1,
OBJC_TAG_NSString = 2,
OBJC_TAG_NSNumber = 3,
OBJC_TAG_NSIndexPath = 4,
OBJC_TAG_NSManagedObjectID = 5,
OBJC_TAG_NSDate = 6,
OBJC_TAG_7 = 7
在剩余的字段中,我们可以赋予他所包含的数据。在 Intel 中,我们 Tagged Pointer 对象的表示如下
OBJC_TAG_7
类型的 Tagged Pointer 是个例外,它可以将接下来后 8 位作为它的扩展类型字段,基于此我们可以多支持 256 种类型的 Tagged Pointer,如 UIColors 或 NSIndexSets 之类的对象。
上文中,我们介绍的是在 Intel 中 Tagged Pointer 的表示,在 ARM64 中,我们情况有些变化。
我们使用最高位代表 Tagged Pointer 标识位,最低位 3 位标识 Tagged Pointer 的类型,接下去的位来表示包含的数据(可能包含扩展类型字段),为什么我们使用高位指示 ARM上 的 Tagged Pointer,而不是像 Intel 一样使用低位标记?
它实际是对 objc_msgSend 的微小优化。我们希望 msgSend 中最常用的路径尽可能快。最常用的路径表示普通对象指针。我们有两种不常见的情况:Tagged Pointer 指针和 nil。事实证明,当我们使用最高位时,可以通过一次比较来检查两者。与分别检查 nil 和 Tagged Pointer 指针相比,这会为 msgSend 中的节省了条件分支。
在 2020 年中,Apple 针对 Objective-C 做了三项优化
通过优化,希望大家可以享受 iPhone 更好,更快的使用体验。
Tips: 类结构的数据变更会在最新的 Runtime 版本中体现,实测 MacOS 10.5.5 中已经存在。 相对方法地址的优化在 Xcode developmentTarget > 14 时会自动进行处理。 Tagged Pointer 的变化则会在 iOS 14, MacOS Big Sur, iPadOS 14 上生效。
本文由哈喽比特于4年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/vSw98xbpEe4pjtBfqFNGAw
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。