Android Studio编译卡慢的解决办法

Google现在最推荐的IDE是Android Studio,用起来很智能,但是也有占用很多内存,运行起来很卡的缺点,下面,我们就来谈谈Android Studio的优化吧。

  • 安装完成后启动卡死
    刚刚打开studio就卡在gradle building的界面再也不动了(去连接墙外的网下载),那么这个时候我们就需要把这个联网下载操作屏蔽掉,找到studio安装目录,找到idea.properties文件,打开,加上下面一行配置,作用是在初次打开的时候不让它连接谷歌进行更新。
disable.android.first.run=true

或者:使用墙外代理。

  • 更改studio的VM大小
    AS限制了Java虚拟机启动的内存大小,限制了最大堆内存,当AS运行越久,内存越不足的时候,就会频繁的触发GC,AS就自然会卡起来了,严重的直接黑屏,所以,我们把对应的所需内存都配置大一些,32位的系统打开studio.exe.vmoptions文件,如果是64位的话打开studio64.exe.vmoptions,改动以下配置,根据各自配置适当调节。
-Xms512m
-Xmx4096m
-XX:MaxPermSize=2048m
-XX:ReservedCodeCacheSize=1024m
  • 使用offline work和Local gradle
    在setting->Build,Execution,Deployment->gradle路径下,选择Use local Gradle distribution,把gradle下载到本地,这样本项目和其他项目用到的时候就不需要重新下载了。项目编译运行成功后,如果依赖配置没有修改,可以设置为offline work,这样重新打开项目时,就不会重新编译了。
    image.png
  • 开启gradle的守护进程
    在工程的gradle.properties文件中,添加以下配置:
# 编译时使用守护进程
org.gradle.daemon=true 
#JVM最大允许分配的堆内存,按需分配 
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m  -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
#使用并行编译
org.gradle.parallel=true  
org.gradle.configureondemand=true
  • 工程尽量减少对module的直接依赖
    将不需要频繁改动的module从setting.gradle中去掉,直接引用module对应的aar文件。工程中有多个module时,会先编译每一个module之后再编译主工程,尽量少的module依赖肯定会加快编译速度。

  • 尽量使用第三方库的jar、aar文件导入自己的项目,或者将第三方库下载到本地,然后当做一个本地模块导入自己的项目,不要再使用gradle中的maven依赖了,具体可以参考Android Studio 编译、同步慢的解决方法

Gradle的生命周期

下面说一下 gradle 的生命周期吧,gradle 构建一个工程主要分为三部分(完全掌握了下面这张图,整个 gradle 的构建过程能了解个十之七八了):

image
  1. 初始化阶段:主要是解析 setting.gradle 文件(因此有人提到减少 setting.gradle 的 module 数量,是很有道理的,但是实际操作过程限制颇多,原因最后会大致说一下);

  2. 读取配置阶段:主要是解析所有的 projects 下的 build.gradle 文件,包括 rootProject 和其他的 subprojects(子项目),检查语法,确定 tasks 依赖以建立 task 的有向无循环图,检查 task 里引用的文件目录是否存在等(这一步也进一步验证了减少 setting.gradle 里的 module 数量可以加快编译速度,因为减少一个 module ,需要解析的 build.gradle 文件就减少一个,第 3 步里就不会执行本属于这个 module 的任务了,但是还是 1 里面说的问题,限制颇多);

  3. 执行阶段:按照 2 中建立的有向无循环图来执行每一个 task ,整个编译过程中,这一步基本会占去 9 成以上的时间,尤其是对于 Android 项目来讲,将 java 转为 class

    compileDebugJavaWithJavac/compileReleaseJavaWithJavac
    
    

    和 将 class 合并成 dex

    transformClassesWithDexForDebug/transformClassesWithDexForRelease
    
    

    这两步很耗时,第一步还好,第二步会耗时非常久。

明确了 gradle 的生命周期,那么就可以看到加快编译速度的关键就是从第三步入手,当然,减少 setting.gradle 里的 modules 数量这一步也是必须的。下面说说我们公司的实践吧。

  1. 项目插件化改造,每位业务上的同学只需要编译一个模块即可,这一点基本上从根本上解决了编译慢的问题(对于大多数没有插件化需求的朋友们可以看下面的一些实践),首先 setting.gradle 里的 module 只有自己开发的模块了,而对应的执行阶段的任务也只有这一个 module 的任务了。

  2. 执行一次 gradle build ,我们就会发现,在这个过程中,其实是执行了多次打包任务的,在 buildTypes 里配置了多个编译打包类型,默认有 debug 和 release ,我们还可以手动配置其他的类型,而且还有 productFlavor 里的多渠道,这样就会执行多次编译打包,而正常开发过程中,只需要打 debug 包去调试,因此使用 gradle assembleDebug 即可,等发版的时候使用其他方式去打多渠道的包(如美团的方案http://tech.meituan.com/mt-apk-packaging.html);

  3. 既然编译主要时间都集中在 gradle 生命周期的第三步执行 task 任务里,那么我们就可以把一些无关紧要的任务给禁用掉,比如各种 Test ,各种 lint 等,刚好在 gradle 里有这样的指令 -x lint 可以临时禁掉 lint 任务,-x test 可以禁掉 test 任务,事实上对于一个稍微大一点的项目,lint 也是很耗时的,当然也可以通过 gradle 脚本彻底禁用 lint 和 test 任务,但是不太建议这么做,因为有时候 lint 和 test 也是挺有用的;

  4. gradle 本身提供了一些指令参数可以加快编译,比如 --daemon ,开启守护进程,--parallel ,开启并行编译等,这个也可以在 gradle.propertites 里配置(编译使用的 jvm 内存也可以在这里配置)。

  5. 定制 gradle 编译流程,利用官方提供的 API 完全可以定制一个适合自己的编译流程,可以参考一下携程的 DynamicAPK/sub-project-build.gradle at master · CtripMobile/DynamicAPK · GitHub,里面有携程他们自己整个完整的编译流程,脚本本身很简单,一共只有两三百行代码。

上面讲到的几点,现有环境就可以做到的大概是这样(有一点要特别注意,如果工程里有交叉依赖,一定不要使用 --parallel 参数):

gradle assembleDebug --daemon --parallel -x lint -x test

,如果是要直接安装到设备上的话,就把 assembleDebug 换成 installDebug ,assembleDebug 可以简写为 asD ,installDebug 可以简写为 iD 。

最后讲一下,为什么减少 setting.gradle 里的 module 数量,确实可以加快编译,但是却限制颇多呢?
首先,我们想一下整个编译过程,先去解析 gradle 配置,建立 tasks 依赖有向图,然后再去执行每一个 module 的 task ,如果我们通过 maven 依赖,使用 aar 替掉了 module(单指 android library),如果我们要改这个 module 里的文件,岂不是每次都要修改上传再下载,这其实还好,但是有一个致命的问题:不修改版本号的话,SNAPSHOT 在 IDEA 里经常会不好使这样就导致修改的东西会不生效,去解决这个问题是非常耗费时间的。不过有一种方式,可以一定程度上解决问题,增加下面的脚本:

project.configurations.all(new Action<Configuration>() {
@Override
    void execute(Configuration files) {
        files.resolutionStrategy.cacheDynamicVersionsFor(5, TimeUnit.MINUTES)
        files.resolutionStrategy.cacheChangingModulesFor(0, TimeUnit.SECONDS)
    }
})

那有人会问,插件化里,每个人开发一个模块,对于每个模块的维护不也是要打包上传到 maven ,每次一有修改,哪怕是非常微小的修改,也要做一次上传,同样会遇到 SNAPSHOT 不好使的问题。

参考文章:
Android Studio编译慢、卡死和狂占内存怎么破?

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

推荐阅读更多精彩内容