一些關于加速Gradle構建的個人經驗
目前絕大多數的Android項目都是基于Grale了,因為Gradle確實給我們帶來了很多便利,然而,在使用了Gradle后,最大的不滿就是編譯起來太慢了。解決慢的問題無非有兩種方法
- 提升硬件配置,選擇CPU和內存和硬盤等更優的硬件
- 在軟件方面,減少不必要的耗時,充分利用現有機器的性能。
本文的主要經驗圍繞著如何減少不必要的耗時操作和如何充分利用機器性能展開。
調整gradle配置
開啟daemon
相比沒有開啟daemon,開啟daemon有如下好處
- 不需要每次啟動gradle進程(JVM實例),減少了初始化相關的工作
- daemon可以緩存項目結構,文件,task等,盡可能復用之前的編譯成果,縮短編譯過程
開啟daemon很簡單,以Mac為例,在家目錄下的.gradle/gradle.properties文件(如沒有,可需要新建文件),加上如下的代碼即可。
org.gradle.daemon=true
或者傳遞gradle參數
./gradlew task --daemon
為了確保gradle配置生效,建議使用gradle —stop停止已有的daemon。
./gradlew --stop
再次執行gradle任務就可以應用daemon了,留意的話,可以看到類似這樣的日志輸出。
Starting a Gradle Daemon (subsequent builds will be faster)
設置heap大小
為Gradle分配足夠大的內存,則可以同樣加速編譯。如下修改文件gradle.properties
org.gradle.jvmargs=-Xmx5120m -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
由于Flipboard依賴繁多,且文件也多,并結合自身設備8G內存,這里為Gradle分配最大5G。效果目前看起來不錯,大家可以根據自己的情況不斷調整得到一個最優的值。
開啟offline
開啟offline之后,可以強制Gradle使用本地緩存的依賴,避免了網絡讀寫操作,即使是需要從網絡進行檢查這些依賴。
./gradlew --offline taskName
如上使用時,加上—offline參數即可。
注意,如果是某個依賴在本地不存在,則會編譯出錯,解決方法,只需要暫時關閉offline,等依賴下載到本地后,在后續的執行中加入offline即可。
設置并行構建
現在的工程往往使用了很多模塊,默認情況下Gradle處理多模塊時,往往是挨個按順序處理。可以想象,這種編譯起來會有多慢。好在Gradle提供了并行構建的功能,可以讓我們充分利用機器的性能,減少編譯構建的時間。
修改gradle.properties文件
org.gradle.parallel=true
或向gradle傳遞參數
./gradlew task --parallel
當我們配置完成,再次執行gradle task,會得到類似這樣的信息,信息標明了開啟Parallel以及每個task使用的線程信息。
./gradlew clean --info Parallel execution is an incubating feature. ....... :libs:x:clean (Thread[Task worker Thread 3,5,main]) completed. Took 0.005 secs. :libs:xx:clean (Thread[Daemon worker Thread 3,5,main]) started. :libs:xxx:clean (Thread[Task worker Thread 2,5,main]) completed. Took 0.003 secs. :libs:xxxx:clean (Thread[Task worker Thread 3,5,main]) started. :libs:xxxxx:clean (Thread[Task worker Thread 2,5,main]) started. :libs:xxxxxx:clean (Thread[Task worker,5,main]) completed. Took 0.004 secs. :libs:json-gson:clean (Thread[Task worker,5,main]) started.
多modules工程優化
現在的一個Project往往有很多modules,導致我們的編譯會變慢。使用—configure-on-demand會在執行任務時僅僅會配置相關的modules,而不是左右的modules。尤其是對于多模塊的project來說,使用起來會有不小的提升。
./gradlew assembleChinaFastDebug --configure-on-demand
嘗試停止已有的daemon
當我們開啟了daemon有段時間后,會發現編譯會變得慢了下來,這時候,我們可以嘗試結束已有的daemon,確保后續的執行任務使用開啟全新的daemon。如下停止已經存在的gradle daemon.
./gradlew --stop Stopping Daemon(s) 1 Daemon stopped
debug構建關閉proguard
提到Proguard大家想到的都是代碼混淆,其實除了代碼混淆之外,Proguard還可以進行代碼壓縮,優化和預驗證。這其中的代碼優化可能會占據更多的時間。 比如一個開啟了代碼優化的配置如下
-optimizationpasses 5
這就意味著這個代碼優化會經過5次,即上一次的優化輸出結果作為下一次的優化的輸入。反反復復的分析,知道完成配置的次數。
在Android中,我們可以配置debug禁用Proguard即可。
buildTypes { debug { minifyEnabled false } release { minifyEnabled true } }
以Flipboard為例,當從設置 optimizationpasses=5 改成debug禁用proguard,編譯時間減少了將近3分多鐘。
進行profile分析
如果上面的所有配置可能到沒有達到明顯的效果,那么我們就應該使用profile功能來分析一下具體卡在哪里了。
gradle提供了性能分析的功能,就profile,使用很簡單,執行任務時帶上—profile參數即可。比如
./gradlew assembleChinaRelease --profile
待到執行完畢,在project根目錄下的build/reports/profile目錄有對應的結果文件,如profile-2017-04-08-23-06-37.html,使用瀏覽器打開,看到的效果是這樣的
從上面的summary可知,上面的主要耗時表現在Task Execution上,于是我們切換到Task Execution這個tab
我們可以發現上面的 :apps:droidyue:crashlyticsUploadDeobsChinaRelease 居然耗費了4m26.26s,那么這是一個什么任務呢?
其實它是著名的bug收集工具crashlytics的上傳混淆映射文件的操作,由于crashlytics的服務器在國外,導致這個網絡操作會很慢。
解決方法是,我們可以選擇性的應用crashlytics插件,具體可以參考 Error-prone,Google出品的Java和Android Bug分析利器 中關于選擇開啟error-prone的部分。
通過profile我們可以清晰地看出耗時的根源在哪里,并開始有的放矢地進行解決。
最后的話
上面關于如果在不提升硬件的條件下進行優化,當我們所有的配置都已經應用,并且仍然感覺編譯時間很長的話,那么我們也應該從硬件的角度去思考了。
關于提升編譯速度的通常主要有三個主要的影響硬件
- CPU,建議CPU不要低于i5
- 內存,建議內存不少于8G
- 硬盤,建議為SSD
以上三者兼備的比較成熟的產品應該是MBP,如這個配置 Apple MacBook Pro 15.4英寸筆記本電腦(Core i7 處理器/16GB內存/256GB SSD閃存/Retina屏) 。
這所謂工欲善其事必先利其器,當我們從硬件和軟件上都下功夫進行了優化,我們的開發效率也會得到很大的提高。
備注:就個人而言,應用上面的方法,日常的debug版本build時間由原來的一分鐘左右降到了30秒左右。我的機器為15.4MBP,i7,8G,SSD.
來自:http://droidyue.com/blog/2017/04/16/speedup-gradle-building/