android工程在越来越复杂后,编译速度会越来越慢,逐渐对开发效率带来很大的影响。
本篇记录一些常见的编译速度优化的方式。
一、 各种常见编译参数的配置和gradle、kotlin版本的更新
网上关于这些编译参数的文档已经非常多了,我这里不想把这些参数再重复讲一遍,也没有这个必要。
大部分对编译速度有帮助的编译参数,都随着gradle版本的升级,变成了默认值。
所以只要把gradle版本升级到最新版本,基本上网上能看到的有用的编译参数都无需再去配置了。
如果有使用kotlin,建议把kotlin相关版本,也升级到最新版本。
另外,jvm相关参数属于例外,通过 org.gradle.jvmargs 配置的相关jvm内存大小等参数,是不会随着gradle版本升级而自动配置的,这个是需要根据自己电脑相关配置调节的。
org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
这是我根据自己电脑配置的jvm参数。
二、通过在gradle编译命令上加--profile --scan
来打开构建性能分析工具
比如原本的编译命令是./gradlew :app:assembleDebug
就改为 ./gradlew :app:assembleDebug --profile --scan
。
编译后点击命令行中输出的链接,就可以打开构建性能分析工具。
这里能看到很多内容,比如有没有开启cache,电脑cpu,jvm最大堆大小,有哪些api应该被废弃了等等。
其中最有用的就是performance这个页面。
在这里可以看到编译耗时在各个阶段的耗时,详细到每个插件的配置、执行,非常有用。
比如这里,可以看到在配置阶段 gav_map.gradle这个脚本执行了0.022s, 这个还是比较短的,如果发现某个脚本执行时间比较长,就可以详细去看看这个脚本,是不是编写的不合理。
一般编译最耗时的是task execution阶段,我们在这个页面可以看到,哪些任务使用了缓存,哪些任务真正执行了,还有各个任务的执行时间。
比如这里可以看到,mergeProjectDexDevDebug
这个任务执行了11秒。
点击它可以跳到Timeline界面,并自动弹出这个任务的详细信息,可以看到,这个任务是因为其中有一个类发生了变化,所以没有使用缓存,重新执行了。
我们就可以看看这个类发生变化是不是符合我们的预期,来选择是否要专门优化。
在这个过程中,可能要花费很多时间,一一排查任务的输入输出是否变化,是否有某些本应使用缓存的任务没使用缓存,是否某些类本来没有更改却被编译系统异常更改了。
这个过程中,往往就能找到办法对编译速度进行提升优化。
三、自定义的插件导致编译速度变慢
通过步骤二的排查后,往往能找到一些通过简单改动就能优化编译速度的途径。
但是也会遇到一些“硬骨头”——自定义的编译插件导致的编译缓慢。
这经常是因为一些编译插件的作者因为对android编译原理的不熟悉,或者因为时间关系,没有好好优化自己的编译插件,导致了编译插件中进行了极其复杂的操作。
这个时候,就需要我们对编译插件进行优化了,首先要先搞明白原本编译插件的原理,然后对它进行改造优化了。
这其中一方面是需要一定的编码基础甚至算法积累,另一方面是需要对编译插件的开发过程有一定了解。
常见的优化方式有 加缓存、使用并发执行、减少冗余步骤,等等。需要根据实际遇到的插件因地制宜的优化。