網站首頁 編程語言 正文
前言
前一陣子公司內部卷了一篇文章大家有興趣的可以看下,大概把我們編譯優化的原理介紹了下,當然其中還有些技術細節相關的并沒有寫。
嗶哩嗶哩Android編譯優化。
基礎知識
Gradle 構建緩存是一種緩存機制,旨在通過重用其他構建產生的輸出來節省時間。構建緩存通過存儲(本地或遠程)構建輸出并允許構建在確定輸入沒有更改時從緩存中獲取這些輸出來工作,從而避免了重新生成它們的昂貴工作。
使用構建緩存的第一個功能是任務輸出緩存。本質上,任務輸出緩存利用了與最新檢查相同的智能,當先前的本地構建已經產生一組任務輸出時,Gradle 使用它來避免工作。但是,任務輸出緩存不僅限于同一工作區中的先前構建,而是允許 Gradle 重用本地機器上任何位置的任何早期構建的任務輸出。當使用共享構建緩存進行任務輸出緩存時,這甚至可以跨開發人員機器和構建代理工作。
除了任務之外,工件轉換還可以利用構建緩存并重用其輸出,類似于任務輸出緩存。
以上內容摘自gradle官方文檔,鏈接如下
我簡單的翻譯下給各位大佬,在本地存在build cache的情況下,gradle task會基于當前的輸入來作為緩存的key值,如果輸入內容沒有發生變更,則意味著本Task可以被跳過,另外這個不同于增量編譯。
又可以偷下官方的圖片了。舉個栗子,JavaCompiler task
的輸入的java文件和上一次編譯的一樣,則意味著該任務可以使用原來編譯輸出作為編譯產物。
Cacheable tasks
任務類型需要使用 @CacheableTask 注釋選擇加入任務輸出緩存。 請注意,@CacheableTask 不被子類繼承。 默認情況下,自定義任務類型不可緩存。
官方有說明什么情況下會使用編譯緩存,首先我們的Task
要被定義成@CacheableTask
。
另外對于Task內部的輸入和輸出也需要打上@TaskInputs
和@TaskOutputs
注解。這樣才能保證當前的Task具備了編譯緩存的能力。
所以想要寫一個能具備緩存能力的Task也是比較復雜的。這也就是為什么Android后面會開始推動Artifacts
的使用了,讓開發盡量可以少關心輸入輸出相關的邏輯。
我們升級適配完AGP 7.0 | 雜談
那么相對的,沒有定義@CacheableTask
的則認為是內有編譯緩存的任務。
TaskOutput
在上述這種被跳過的任務哦,一般都會有在Task編譯完成之后帶上一些特殊的標識符。
-
(no label) or EXECUTED
任務正常執行了。 -
UP-TO-DATE
任務輸出沒有變更。 - 輸入輸出均沒有發生變更。
- 任務執行了,但是任務告訴gradle輸出并未發生變更。
- 任務沒有執行和一些依賴項,但所有依賴項都是最新的、已跳過或來自緩存。
- 任務沒有執行也沒有依賴。
-
FROM-CACHE
任務的輸出可以從之前的執行中找到。任務已從構建緩存恢復輸出。 -
SKIPPED
該任務沒有被執行。任務已明確從命令行中排除。 -
NO-SOURCE
當前無需執行該任務。輸入內容并沒有源文件,比如.java
簡單的來說,除了第一種情況以外,其他的都是任務被跳過。
有趣的編譯問題
好了,有了前置的知識儲備的情況下,我們就可以展開說一下我們最近碰到的一個奇怪的問題了。
我們有個protobuf
編譯的倉庫,專門負責將pb文件轉化成java或者kotlin。然后會把這些生成的文件移動到另外兩個模塊進行打包,最后刪除生成的所有類文件。然后再去執行javacompiler task。
這個模塊出現了一個二次編譯的問題。第一次打包protobuf
模塊的時候編譯是正常的,然后當二次編譯該模塊的情況下,該模塊就會出現類丟失的問題。
問題分析
這個問題分析起來就比較簡單。在二次編譯的情況下呢,因為輸入的內容并沒有發生變更,所以觸發了Gradle Task
相關的緩存,然后所有的pb文件轉化成java kt的過程就被跳過了。但是呢后續的copy task因為本身不具備緩存能力,所以他還是會執行一次cv的任務。但是原來生成的java和kt已經被刪除了。這個時候他就會把空的文件夾進行一次覆蓋操作。之后就導致了原來的java和kt文件全部丟失的問題。
這就是一個很有趣的build cache
導致的奇形怪狀的問題,因為上一個任務具備了編譯緩存,之后跳過了編譯直接用了原來的output輸出。但是呢下一個任務非緩存的,所以必然還是會執行拷貝任務。
至于解決方案我就不寫了,感覺大家應該沒啥興趣。
最后
重要的事情再說一遍,前一陣子在公司內部卷了一篇文章大家有興趣的可以看下,大概把我們編譯優化的原理介紹了下,當然其中還有些技術細節相關的并沒有寫。
https://www.jb51.net/article/252481.htm
原文鏈接:https://juejin.cn/post/7096725498943766565
相關推薦
- 2022-09-16 Go+Kafka實現延遲消息的實現示例_Golang
- 2022-08-20 Python超詳細講解元類的使用_python
- 2022-11-28 詳解Rust中的變量與常量_Rust語言
- 2022-07-27 Python中range函數的使用方法_python
- 2024-03-18 Springboot如何判斷pom.xml中是否加載了某個jar依賴
- 2023-12-07 redis key
- 2022-08-27 C語言數據結構之棧與隊列的相互實現_C 語言
- 2022-09-19 Tomca啟動閃退問題解決(八大類)_Tomcat
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支