iOS 代码使用 C++ 的 zero-cost abstraction 特性

不少 iOS 项目里都有 C++ 代码的痕迹,Objective-C 和 C++ 虽然都是 C 的 superset,但二者在语言特性上存在很大差异,Objective-C 的 runtime 使其语言的特性更丰富更易使用,但代价是会增加性能损耗以及编译后的 binary size。

很多成熟项目开发到一定阶段,会关注一些关键指标,比如 App size,现在超过 100 M 的 App 比比皆是,而 App Store 上超过 150 MB 的 App 只能通过 Wifi 下载,当常规的瘦身手段用尽之后,App size 每一个 MB 的减少都弥足珍贵,这篇文章向 iOS 开发者介绍 C++ 的 zero cost abstraction 特性,在特定的场景下使用能起到立竿见影的疗效:减小 iOS App 的 binary size,给 App 瘦身。

zero-cost abstraction

Objective-C 和 C++ 同为面向对象语言,我们通过对象来抽象世界中的概念,但 Objective-C 的抽象伴随着代价,抽象越多,定义的类越多,最后编译出的 binary size 也就越大,而 C++ 却没这方面的烦恼,无论你定义多少类,设计多少 component,采用多少设计模式,并不会增加最后的 binary size,也就是所谓的 zero-cost,对 iOS 开发者来说,这种理论听起来可能有些反常识,但如果你是先学习 C, C++,再接触 Objective-C 的 runtime,理解起来再直白不过。

举例来说,假设我们从服务器收到一段请求 user 信息的 response,一般我们会将 response 还原成一个业务 model 对象,user 类的定义如下:

class User { int gender; int age };

如果使用 C++ 来定义这个类,在 C++ 编译器的眼里,这个类的全部信息不过是两个连续存在于内存空间上的 4 个字节(假设一个 int 占 4 字节)。我们访问 user 对象的代码:

int age = user->age;

会被编译器翻译成一段类似如下的内存访问代码:

r11 = *(r10 + 0x4)

在编译器眼里没有类的概念,只有内存地址,偏移量,以及读写操作。即使我们加入更多的抽象,比如把 User 类放进 Car 类里面,再把 Car 放进 City 类里,当我们使用 city->car->user->age 时,编译器依旧会将代码翻译成直白的 memory access。

如果我们使用 Objective-C 来书写上述代码,情况就完全不一样了,熟悉 Objective-C runtime 的同学明白接下来会发生一系列操作,编译后的代码里,Objective-C 的 runtime 会先尝试给 user 对象发送 message(如果是通过 property 访问),需要通过 user 对象的 isa 指针找到 User 类定义,再通过 selector 在 cache 里找到 IMP 地址,最后才从函数返回需要操作的目标内存地址。我只列出了关键的几步,中间其实省略了 n 个流程,类越多,抽象的层次越多,步骤也就越多,这是由于 Objective-C 需要将 class 的定义编译进最后的 binary 里,需要依赖 class 的信息来实现 runtime 的一些机制,class 越多,最后生成 binary 自然也就越大。

简而言之,大部分编程语言和 Objective-C 类似,由于需要在 binary 中保存 class 的信息,而将抽象的成本带入了编译后的机器码。通过上面的分析我们也不难发现 zero-cost abstraction 的好处体现在两方面,一是 binary 更小,二是运行时更高效(没有一层层的中转)。

C++ 的 zero-cost 特性得益于编译器的高效实现,我们在代码里定义的所有类,最后都会被编译器降维,高楼被夷为平地,信息却不会丢失,编译器用一片二向箔将面向对象的世界压扁成一幅画,画里的机器码仍然能严格准确的表达我们的意图。

谨慎使用

使用 zero-cost abstraction 的代价即为使用 C++ 开发的代价,C++ 使用难度高于 Objective-C,过多引入 C++ 代码可能会造成纯 iOS 团队的维护效率降低,在引入之前,最好有准确的评估和 demo 先行验证。

By “zero-abstraction” I mean not a byte and not a cycle wasted compared to hand-crafted low-level alternatives. Often the overhead of a function call (and especially an indirect function call) is considered too much. Offering both hardware access and abstraction is the basis of C++. Doing it efficiently is what distinguishes it from other languages.

​ -Bjarne Stroustrup

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容