提高android gradle构建速度的努力

目前看, gradle命令行选项, 使用jack(想绕过class->dex这步), 以及取消lint, multi-dex, proguard(这三样确实耗时, 但不是最关键的), 都不能显著提供android-gradle-plugin的构建速度(assembleDebug为例), 耗时就是出在了dexDebug(50多秒), packageDebug(10多秒)这两个任务上(android-gradle-plugin:1.3.0为例), 既然是dex, 我尝试了dexOptions, 发现真的可以.

添加以下代码到build.gradle能提高构建速度:

dexOptions {
    incremental true //如果开启multi-dex, 此句无效
    preDexLibraries true
    javaMaxHeapSize "4g" //最主要是这句, 不过改成8g没有更显著的提升
//  jumboMode true
//  threadCount 8 //gradle输就输在了并行上, 都是串行, 增加线程数没鸟用
//  maxProcessCount 8 //com.android.tools.build:gradle:2.0.0
}

既然堆大小有这样显著的效果, 那我想能不能提高gradle环境的内存使用大小, 于是在gradle.properties中做了如下配置:

org.gradle.parallel=true
org.gradle.daemon=true
org.gradle.configureondemand=true
# default workers count equals processor count
# org.gradle.workers.max=8
org.gradle.jvmargs=-Xms4096m -Xmx8192m -Dfile.encoding=UTF-8

但是前几个在处理configuration依赖速度有所提高, 不过我认为最关键的那个jvmargs, 不知道是不是默认值就已经很高了? 反正加上以后没有看到有多大的提升;

(以上构建速度的测试包括是通过终端gradle命令的--profile获取的)


这是原来:
这里写图片描述
这是现在:
这里写图片描述


总结: 技术上, 构建有了显著提升(缩短了20多秒), 但感官上, 从1min10s到48s, 给人感觉还是慢, 升级android-gradle-plugin也还是慢(因为跟gradle本身没多大关系, 而取决于android-gradle-plugin), 比android的”ant”构建, facebook的”buck”构建慢很多;

小弟感觉android studio 2.0最主要的不是通过提高gradle-plugin的性能来提速的, 而是想通过instant run(目前好像还没做好, 有时改动烧进去没变化), 即在install apk上, 少做拷贝apk(越大越慢)然后pm install -r, 取而代之的是, 保持一个连接, 本地代码的变化通过差异索引得知, 然后通过dexclassloader重新载入, 换句话说, 很像热补丁代替静态升级的做法.

对我来说, ant太过低级(类似makefile, 所有要亲力亲为), buck要求在每个目录下都有配置文件, 学习成本也不便宜, 且目前还不支持windows, 这两种都不是最好的选择, gradle表现不给力, 从未知性上, 以及兼容android studio, intellij idea, eclipse adt的角度, 想再看看maven方式是否能编译的快些, 只希望比gradle快些就行, 结果让人很失望, 不仅没快多少, 而且损失也很明显: 不能用ide的一键按钮安装, 而是手动install apk; 非官方构建, 需要维护两套兼容构建配置;

其实还一个建设性的方法: 通过划分多模块/多apk来减少依赖的反复构建;

另外我注意到jumbo mode这个概念, 它是指dx –force-jumbo, 原文意思是:

it is about the opcode such that “op vAA, string@BBBBBBBB” versus “op vAA, string@BBBB”, 32 bits versus 16 bit.

将其设置为true, 可解决以下警告:

AGPBI: {"kind":"SIMPLE","text":"UNEXPECTED TOP-LEVEL EXCEPTION:","position":{},"original":"UNEXPECTED TOP-LEVEL EXCEPTION:"}
AGPBI: {"kind":"SIMPLE","text":"com.android.dex.DexIndexOverflowException: Cannot merge new index 65772 into a non-jumbo instruction!","position":{},"original":"com.android.dex.DexIndexOverflowException: Cannot merge new index 65772 into a non-jumbo instruction!"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.merge.InstructionTransformer.jumboCheck(InstructionTransformer.java:109)","position":{},"original":"\tat com.android.dx.merge.InstructionTransformer.jumboCheck(InstructionTransformer.java:109)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.merge.InstructionTransformer.access$800(InstructionTransformer.java:26)","position":{},"original":"\tat com.android.dx.merge.InstructionTransformer.access$800(InstructionTransformer.java:26)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.merge.InstructionTransformer$StringVisitor.visit(InstructionTransformer.java:72)","position":{},"original":"\tat com.android.dx.merge.InstructionTransformer$StringVisitor.visit(InstructionTransformer.java:72)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.io.CodeReader.callVisit(CodeReader.java:114)","position":{},"original":"\tat com.android.dx.io.CodeReader.callVisit(CodeReader.java:114)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.io.CodeReader.visitAll(CodeReader.java:89)","position":{},"original":"\tat com.android.dx.io.CodeReader.visitAll(CodeReader.java:89)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.merge.InstructionTransformer.transform(InstructionTransformer.java:49)","position":{},"original":"\tat com.android.dx.merge.InstructionTransformer.transform(InstructionTransformer.java:49)"}
...

哎~ 看来android gradle plugin, 目前只能忍着吧.

后记:

  • dexOptions.threadCount为什么不起作用, 原来源码中说有问题给注掉了, 坑爹啊! 见com.android.builder.core.AndroidBuilder.java
    这里写图片描述

  • dexDebug执行的具体命令如下, 注意每次哪怕代码有一行更新, 其后构建都删掉重建allclasses.jar[它是在:app:packageAllDebugClassesForMultiDex任务中生成的, 另一个jar包componentClasses.jar则在:app:shrinkDebugMultiDexComponents任务中生成], 然后将这个jar搞成一个或多个dex, 目前没有任何重用, dexOptions中的增量也只对非multi-dex方案有效, 这是瓶颈所在啊!

java -Xmx4g -Dfile.encoding=UTF-8 -Duser.country=CN -Duser.language=zh -Duser.variant -cp ${ANDROID_SDK_HOME}/build-tools/23.0.1/lib/dx.jar com.android.dx.command.Main --dex --verbose --num-threads=4 --multi-dex --main-dex-list ${PROJECT_ROOT}/app/build/intermediates/multi-dex/debug/maindexlist.txt --output ${PROJECT_ROOT}/app/build/intermediates/dex/debug ${PROJECT_ROOT}/app/build/intermediates/multi-dex/debug/allclasses.jar
  • 发表一点感想. 仅对我来说, gradle的multi-dex方案感觉很戏谑, 因为它, dex的生成没法做到增量, 还要通过切换minsdkversion来换取构建速度的微弱提升, 它是你当初没有做好多项目模块化插件化, 然后被65535问题惊醒时所做的懒人决定, 你渴望让构建工具替你分出多个dex, 你渴望不要再有其他麻烦, 它也确实如你意, 这么做了, 可是它要建立在allclasses.jar这样一个瓶颈上, 而且它的根本却还是要靠dexclassloader, 于是你不得不用更多的编译时间一天天偿还你当初的懒惰, 弥补你系统前瞻性设计的缺乏;

  • 网上查到可以通过这样的方式在调试时加快构建速度, 各位看官可以品尝:
    这里写图片描述

猜你喜欢

转载自blog.csdn.net/kslinabc/article/details/51166364