Android Studio编译慢、卡死和狂占内存怎么破?
https://www.zhihu.com/question/27953288
链接:https://www.zhihu.com/question/27953288/answer/118031242
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Android Studio 本就占内存,设备烂卡死是必然的,要解决卡死的问题,一定要升级硬件设备。其他人说的答案迷惑性还都挺强的,然而都是一定程度上加快编译速度,并不能解决卡死的问题,也没有人能够解释为什么那样做可以加快编译速度。
至于加快编译速度,有一句说一句,我觉着一些答主的答案适用性都并不强,其实还是应该从 gradle 入手,讲的有什么不合适的地方,还请轻喷,有什么问题也可以留言。
以下我讲到的所有步骤,推荐都在终端里执行。在终端里执行编译有很多好处:
- 可以观察到整个编译过程,有助于理解 gradle 构建流程;
- 可以看到编译过程中哪些任务比较耗时,可以对编译慢的问题对症下药;
- 可以随时终止编译,如果被卡在某个阶段,ctrl + c 可以随时终止编译,在 Android Studio 里也终止编译,但是基本上十次有九次都会失败;
- 因为是在终端里,对 Android Studio 影响极小,基本不会造成 Android Studio 卡顿;
- 不会遇到 Android Studio 的各种 bug 。
先说一下 gradle 的生命周期吧,gradle 构建一个工程主要分为三部分(完全掌握了下面这张图,整个 gradle 的构建过程能了解个十之七八了):
- 初始化阶段:主要是解析 setting.gradle 文件(因此有人提到减少 setting.gradle 的 module 数量,是很有道理的,但是实际操作过程限制颇多,原因最后会大致说一下);
- 读取配置阶段:主要是解析所有的 projects 下的 build.gradle 文件,包括 rootProject 和其他的 subprojects(子项目),检查语法,确定 tasks 依赖以建立 task 的有向无循环图,检查 task 里引用的文件目录是否存在等(这一步也进一步验证了减少 setting.gradle 里的 module 数量可以加快编译速度,因为减少一个 module ,需要解析的 build.gradle 文件就减少一个,第 3 步里就不会执行本属于这个 module 的任务了,但是还是 1 里面说的问题,限制颇多);
- 执行阶段:按照 2 中建立的有向无循环图来执行每一个 task ,整个编译过程中,这一步基本会占去 9 成以上的时间,尤其是对于 Android 项目来讲,将 java 转为 class
compileDebugJavaWithJavac/compileReleaseJavaWithJavac
和 将 class 合并成 dex
transformClassesWithDexForDebug/transformClassesWithDexForRelease
这两步很耗时,第一步还好,第二步会耗时非常久。首先在 gradle.properties 里设置
org.gradle.jvmargs=-Xmx4096m //越大越好
,然后在工程的 build.gradle 里的 android 结点下增加 dexOptions 配置,如下:
dexOptions {
dexInProcess true
preDexLibraries true
javaMaxHeapSize "4g"//越大越好
incremental true
}
明确了 gradle 的生命周期,那么就可以看到加快编译速度的关键就是从第三步入手,当然,减少 setting.gradle 里的 modules 数量这一步也是必须的。下面说说我们公司的实践吧。
- 项目插件化改造,每位业务上的同学只需要编译一个模块即可,这一点基本上从根本上解决了编译慢的问题(对于大多数没有插件化需求的朋友们可以看下面的一些实践),首先 setting.gradle 里的 module 只有自己开发的模块了,而对应的执行阶段的任务也只有这一个 module 的任务了。
- 执行一次 gradle build ,我们就会发现,在这个过程中,其实是执行了多次打包任务的,在 buildTypes 里配置了多个编译打包类型,默认有 debug 和 release ,我们还可以手动配置其他的类型,而且还有 productFlavor 里的多渠道,这样就会执行多次编译打包,而正常开发过程中,只需要打 debug 包去调试,因此使用 gradle assembleDebug 即可,等发版的时候使用其他方式去打多渠道的包(如美团的方案http://tech.meituan.com/mt-apk-packaging.html);
- 既然编译主要时间都集中在 gradle 生命周期的第三步执行 task 任务里,那么我们就可以把一些无关紧要的任务给禁用掉,比如各种 Test ,各种 lint 等,刚好在 gradle 里有这样的指令 -x lint 可以临时禁掉 lint 任务,-x test 可以禁掉 test 任务,事实上对于一个稍微大一点的项目,lint 也是很耗时的,当然也可以通过 gradle 脚本彻底禁用 lint 和 test 任务,我也在一些微信群里分享过相关代码,但是不太建议这么做,因为有时候 lint 和 test 也是挺有用的;
- gradle 本身提供了一些指令参数可以加快编译,比如 --daemon ,开启守护进程,--parallel ,开启并行编译等,这个也可以在 gradle.propertites 里配置(编译使用的 jvm 内存也可以在这里配置)。
- 定制 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 不好使的问题。嘿嘿,这个问题嘛,我司自己维护了一个 gradle 插件,已经解决了,至于解决方案,是公司机密,我是不会讲的。
然后,还有一点,我相信大部分开发者平常开发都是单 module 的,多 module 的情况并不多,因此大多数依赖基本也都是 aar 或者 jar ,根本就不存在所谓的将 library 转成 aar 上传的情况,因此一些答主说的根本毫无意义,这也是为什么我会说影响编译速度的情况主要集中在 gradle 生命周期的第三个阶段,至于第三个阶段的优化,看我上面的答案就好了。
Android Studio编译慢、卡死和狂占内存怎么破?的更多相关文章
- android studio 编译加速
1. http://www.52codes.net/article/658.html 2.http://my.oschina.net/sammy1990/blog/388846 3.http://st ...
- 手把手图文并茂教你用Android Studio编译FFmpeg库并移植
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52661331 之前曾写过一篇&l ...
- Android studio 编译失败Error:Could not read entry ':app:processDebugManifest' from cache taskArtifacts.b
Android studio 编译失败 Error:Could not read entry ':app:processDebugManifest' from cache taskArtifacts. ...
- 【Android】Android studio 编译问题:finished with non-zero exit value 2
1.Android studio 编译问题:finished with non-zero exit value 2 问题: Error:Execution failed for task ':andr ...
- 我的Android进阶之旅------>解决Android Studio编译后安装apk报错:The APK file does not exist on disk
1.错误描述 今天用Android Studio编译应用后安装APK的时候,报错了,错误如下所示: The APK file build\outputs\apk\OYP_2.3.4_I2Base_64 ...
- Android Studio编译卡死
首先,用AS,你必须fanqiang,其它都是次要的. AS/bin/*.exe.vmoptions ## *DO NOT* modify this file directly. If there i ...
- 怎么解决Android studio导入项目卡死
在使用Android studio的时候常常遇到这样的问题,从github或是其他地方导入项目,Android studio呈现卡死的现象!当遇到这种情况时,可以看看是下面那种情况,在按照方法来解决! ...
- Android Studio编译FBReaderJ
我的个人环境 系统:mac (windows应该差不多) 工具:android studio 2.1.2 注意:一定要安装NDK!一定要安装NDK!一定要安装NDK! 如何安装NDK ...
- 解决Android studio导入项目卡死
在使用Android studio的时候常常遇到这样的问题,从github或是其他地方导入项目,Android studio呈现卡死的现象!当遇到这种情况时,可以看看是下面那种情况,在按照方法来解决! ...
随机推荐
- java中的悲观锁和乐观锁实现
悲观锁就是认为并发时一定会有冲突发生,采用互斥的策略.比如java中的synchronized. 而乐观锁是假设并发时不会有冲突发生,如果发生冲突,则操作失败,并不断重试.乐观锁的机制就是CAS(Co ...
- IOS子视图超过父视图frame后,无法交互响应
确定第一响应者 当用户触发某一事件(触摸事件或运动事件)后,UIKit会创建一个事件对象(UIEvent),该对象包含一些处理事件所需要的信息.然后事件对象被放到一个事件队列中.这些事件按照先进先出的 ...
- 科学计算三维可视化---TraitsUI(配置视图)
配置视图 模态窗口: from traits.api import HasTraits,Int,Strclass ModelManager(HasTraits): model_name = Str c ...
- Spring 手动提交事务
在使用Spring声明式事务时,不需要手动的开启事务和关闭事务,但是对于一些场景则需要开发人员手动的提交事务,比如说一个操作中需要处理大量的数据库更改,可以将大量的数据库更改分批的提交,又比如一次事务 ...
- MongoDB - MongoDB CRUD Operations, Delete Documents
Delete Methods MongoDB provides the following methods to delete documents of a collection: Method De ...
- jdk1.8.0_45源码解读——LinkedList的实现
jdk1.8.0_45源码解读——LinkedList的实现 一.LinkedList概述 LinkedList是List和Deque接口的双向链表的实现.实现了所有可选列表操作,并允许包括null值 ...
- Linux基础操作-分区概念
开启Linux系统前添加一块大小为20G的SCSI硬盘 开启系统,右击桌面,打开终端 为新加的硬盘分区,一个主分区大小为10G,剩余空间给扩展分区,在扩展分区上划分两个逻辑分区,大小各5G 进入分区工 ...
- 【转换】Bean、List、Map、Array、String与JSON字符串的相互转换
import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.math.BigDecimal; i ...
- MUI上拉加载下拉刷新
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- [转] A*寻路算法C++简单实现
参考文章: http://www.policyalmanac.org/games/aStarTutorial.htm 这是英文原文<A*入门>,最经典的讲解,有demo演示 http: ...