常见的Android编译优化问题
编译常见问题
在开发进程中,有碰到过一些由于编译优化导致的代码修改并不符合咱们预期的情况。这也便是之前为什么我经常说编译产品其实是不太能够被信任的。
- 办法签名改变,底层仓库的办法改变但是上层模块并没有跟从一起从头编译导致的这个问题。
- 常量优化,将一些常量的调用点直接替换成常量的值。
- 删去空导包, 没有用的一些导包就会做一次剔除。
最近倒运了
咱们最近碰到一个pipeline
相关并且很妖怪的问题。咱们一个pipeline
会检查apk产品中是否存在反常的办法调用,便是之前介绍的在R8的基础上开发出来的A8。但是最近有一个类被删去了之后呢,但是代码中还有一处调用点。但是这个检测竟然被通过了,然后这部分代码就被合入了master。
这个引证的文件就如上图所示,是一个debug buildType
中的,所以并不是一切的apk中都会存在这部分代码。
然后呢,这个MergeRequest
就被合入了master
分支,由于当天是咱们出下一个版本包的时刻,然后交付给测验的便是全量编译的debug
和release
包。其他开发同学rebase完master之后就发现piepline
都跑不过了,就导致了他们当天的代码无法被合入。
这个便是事情大约的原因和经过,但是各位有没有想过为什么会发生这个问题吗。这个是不是咱们的pipeline
呈现了bug,导致了这种问题无法被辨认出来了呢。
以前有说过,假如简略的说咱们的快编系统便是把模块替换成对应的aar,从而到达编译提速。所以由于咱们运用的是这个模块对应的aar产品,所以大约率便是由于这个模块的编译产品和源代码有差异导致了这个问题。
其实这个问题一呈现我就已经知道大约率是由空导包优化导致的这个问题,由于在pipeline
检查的时候,检测的apk产品中的确不存在这个导包。由于咱们运用的是一个历史版本的aar,其间无效导包的部分已经被编译器做了删去空导包的优化了。接下来咱们看下我写的一个demo中的无效导包。
图一呢是源代码java文件,图二呢则是jar包中的代码。能够简略的看出来行号呢是能够对应的上的,但是这个AppCompatActivity
的无效导包在产品中已经被优化掉了。这里也就回答了在编译进程中会保留行号,但是也会优化掉一部分不需要的代码,让咱们编译出来的产品更小。
所以也就导致了咱们的产品和咱们的源代码之间的差异,另外一个角度便是说从apk中咱们的确是不存在这个类的导包。但是呢在咱们把这部分代码从头编译成aar的时候,就会呈现source缺失,导致的语法树无法生成,之后导致的编译失利问题。
这也便是所以我一向和咱们说编译产品是不能够被信任的呢。
以前倒运过
这个是之前的一个故事了,咱们之前呢在模块中定义了一些静态常量吧,然后用来标识其时SDK的版本,然后这个值在其他模块中被引证到了。
有一次由于需求改变,咱们更改了这个静态变量的值,然后呢我就把这个需求提测了。之后测验反应给我为什么这边的这个值没有变化啊。
我的天,其时我便是这样,发生了什么情况。然后呢我全量打了个包好了,我其时也就以为只是编译时的一个bug罢了。然后后来呢,我查了下材料发现这个便是一个java编译时的常量优化问题。过了一阵子吧,我面试了下字节跳动,然后我和面试官也聊了下这个话题,然后呢在这个办法签名改变的问题上,其时我略输一筹,哈哈哈哈。接下来咱们就看下一个demo。
图1呢也是java代码,图2呢则是aar中的编译产品。其间咱们能够看到,这个静态常量在编译成产品之后就会被编译成这样。
所以这个就解说了我一开始碰到的这个问题,他便是由于咱们的编译器已经把aar中的这部分静态常量编译成了直接的值,然后呢咱们的源变化之后假如没有从头编译对应的模块,就会导致这个值一向无法被更新到最新的值。
定论
假如咱们对安卓编译相关有爱好的话,这些问题很可能都会在面试的时候被问到。希望这不仅仅只是一篇我对于这些问题的考虑,也能对各位有所帮助吧。