杂谈-通过编译器优化代码

前段时间有人问我,如何考虑编译优化。我想了想,但是因为自己没有学过这方面的课程,也没有总结出成套的体系(毕竟自己一共就只吃了几年程序员的),所以,只能告诉他,“把自己当做编译器的作者。当编译器的作者面对自己的代码时,他能做些什么”

扯淡结束,下面通过一个小例子讲讲“为什么 Objective-C 难以进行优化”。

Objective-C 是 C 的超集,语言创作者通过给 struct 添加了一些 function,把 struct 升级为了 class。当然,实际情况不会像我说的这样简单,肯定会更加复杂,但我这里只是讲和下文相关的内容。

struct 升级为了 class,function 也“一人得道鸡犬升天”地升级为了 method。

很多 iOS 开发者都无法区分“函数”和“方法”。实际上,把它们翻译为 function 和 method 可能区分度更高一些。

可以粗糙的用以下等式区别它们:

类 = 含有特殊字段的结构体 + 其它
method = function + 类的引用 + 其它

首先,稍微解释一下第一个等式。类经过编译后,会被打散到 mach-o 的多个地方。其中,一份信息会存储到 mach-o 的 __DATA,__objc_data 字段。

如下图。

杂谈-通过编译器优化代码_第1张图片

Objective-C 中的 method 被编译后,会被当做函数处理,与此同此,编译后的 mach-o 文件也会保留一些特殊信息。

如下图,第一幅图表示:method 编译后,会在 段__TEXT,__text 生成一个对应的函数。第二幅图表示:这是一个函数。第三幅图表示:method 与 class 之间的关系会被存储到 段 __DATA,__objc_const

杂谈-通过编译器优化代码_第2张图片
1
杂谈-通过编译器优化代码_第3张图片
2
杂谈-通过编译器优化代码_第4张图片
3

我们先回顾一下它们的用法。

简单来说,类似于 [[NSObject alloc]init] 的写法都是在调用 Objective-C 中“类”或“类的实例”的 method,而 int result = pow(x,y) 属于调用 function 的过程。

考虑这样一种情况,如果某个类,它的某些方法没有被编译器检测到调用,比如没有检测到[object aMethod]这种用法。编译器是否该把这个方法的实现从编译后的 mach-o 文件内移除,从而减小可执行文件的体积,提到可用的内存空间,加快载入速度?

答案是:“非常不推荐这样做”。Objective-C 是一门动态语言,除了直接调用外,还有大量的动态调用方式。仅仅因为编译器检测不到调用就进行移除是非常危险的行为。

再考虑这样一种情况,如果某个函数,它没有被编译器检测到被调用,比如没有检测到 int result = pow(0,0)。编译器是否该把这个函数的实现从编译后的 mach-o 文件内移除,从而减小可执行文件的体积,提到可用的内存空间,加快载入速度?

答案是:“非常推荐这样做”。虽然通过某些方案也可以动态调用
c 函数,但是,很显然,这样行为非常非常少,程序员有义务自己处理这种情况或者关闭优化器。

类似的,因为 Objective-C 可以动态添加 method 的原因,编译器不能直接把 [objc superMethod] 替换为 直接执行函数superMethod(objc,...),而是需要通过递归地查找方法列表,检测该方法是否被某一个父类动态添加了实现。

综上,一个动态性非常强的语言是很难依靠编译器作者的智慧进行优化的,所以,苹果才会从零开始发明一种新的编程语言。

参考文章:https://llvm.org/svn/llvm-project/cfe/branches/ggreif/CallInst-operands/test/CodeGenObjC/metadata-symbols-64.m

你可能感兴趣的:(杂谈-通过编译器优化代码)