[TOC]
## Android虛擬機
### android2.2~android4.4(JIT與Dalvik)
JIT是運行時編譯,這樣可以對執行次數頻繁的dex代碼進行編譯和優化,減少以后使用時的翻譯時間,雖然可以加快Dalvik運行速度,但是還是有弊病,那就是將dex翻譯為本地機器碼也要占用時間。
*****
JIT是"Just In Time"的縮寫,就是"即時編譯技術",與Dalvik虛擬機相關
我們使用Java開發android,在編譯打包APK文件時,會經過以下流程
* Java編譯器將應用中所有Java文件編譯為class文件
* dx工具將應用編譯輸出的類文件轉換為Dalvik字節碼,即dex文件
* 之后經過簽名、對齊等操作變為APK文件。
Dalvik虛擬機可以看做是一個Java VM,他負責解釋dex文件為機器碼,如果我們不做處理的話,每次執行代碼,都需要Dalvik將dex代碼翻譯為微處理器指令,然后交給系統處理,這樣效率不高。
為了解決這個問題,Google在2.2版本添加了JIT編譯器,當App運行時,每當遇到一個新類,JIT編譯器就會對這個類進行編譯,經過編譯后的代碼,會被優化成相當精簡的原生型指令碼(即native code),這樣在下次執行到相同邏輯的時候,速度就會更快。
### android4.4~android5.0(Dalvik和art并存)
Google在4.4之后推出了ART,用來替換Dalvik。4.4之后兩種運行時環境共存(JIT 和 ANR),可以相互切換,但是在5.0+,Dalvik虛擬機則被徹底的丟棄,全部采用ART.
### android5.0+(art)
ART的策略與Dalvik不同,在ART 環境中,應用在第一次安裝的時候,字節碼就會預先編譯成機器碼,使其成為真正的本地應用。之后打開App的時候,不需要額外的翻譯工作,直接使用本地機器碼運行,因此運行速度提高。
當然ART與Dalvik相比,還是有缺點的。
* ART需要應用程序在安裝時,就把程序代碼轉換成機器語言,所以這會消耗掉更多的存儲空間,但消耗掉空間的增幅通常不會超過應用代碼包大小的20%
* 由于有了一個轉碼的過程,所以應用安裝時間難免會延長。
### android7.0+(ART 即時 (JIT) 編譯器)
一個 app 在安裝時會生成相應的 oat 文件。在運行時,會加載其 oat 及 dex 文件。執行一個方法,可能有三種模式:**解釋執行**、**執行 oat 機器碼**、**JIT**。
Android 7.0 之后,為了加載 app 的安裝速度,安裝時生成 oat 文件只會做 smali 指令優化等少量優化工作,并不會立刻生成 oat 機器碼。這也意味著 app 在安裝之初運行是解釋執行為主的。
在解釋執行過程中,ART 會記錄每個方法的調用次數,記錄在方法對應的 ArtMethod 中。這個次數即該方法的熱度。方法的熱度達到設定值之后,這個方法會被標記為**熱代碼**,并觸發 JIT,在運行時編譯生成機器碼,以便下次調用時直接執行機器碼。這些熱代碼還在被記錄到 app 的 profile 中,以便之后重新 oat 時編譯這些熱代碼。
方法的三種執行模式可以在運行時動態切換,實際上同一進程中三種模式往往是共存的,而且同一方法的運行模式也可能隨時切換。
## 內聯優化
### 什么是內聯及內聯的生成時機
內聯所做的事情就是
* 縮短調用鏈
* 縮短代碼
* 提高運行速度
### 常見的內聯類型
比較常見的內聯類型有常量內聯,字符串內聯以及方法內聯等常量內聯
#### 常量內聯
修飾的靜態常量值直接替換到代碼塊里面,比較常見的是作用于編譯期,可以體現在.class文件中。
#### 方法內聯
方法內聯是將被調用方的代碼拷貝到調用方的調用處,從而減少代碼函數定義及函數跳轉等,提高運行效率。
根據我們下文的對生成時機的區分,還可細分為編譯期內聯優化,dex2oat內聯優化和JIT內聯優化
##### 1\. 編譯期內聯優化(混淆優化工具R8)
當Android Gradle插件升級至3.4.0,會引入一個新的混淆優化工具R8,這個工具可以對代碼進行壓縮優化,其中就包括了選擇性內聯。
(脫糖)Desugaring的工作原理是 R8/D8在字節碼編譯成Dex文件時,通過三方庫的引入支持了原本不支持的高版本JDK語法,并一同打進dex,使之可以正常工作
使用R8優化包體積
R8在D8的基礎上又增加了Proguard的能力,通過開啟Shrinking,可以對源碼進行優化,以達到減小包體積的目的,具體包括但不限于:
* 代碼刪除:通過語法樹靜態分析技術,發現并剔除未使用的代碼,例如沒有被實例化的Class等
* 代碼優化:對運行時代碼進行優化,包括死代碼刪除、未使用的參數刪除、選擇性內聯、類合并等。
* 代碼混淆:優化標識符名字,減少代碼數量,例如MyAwesomeClass可能被優化成單一字母a
##### 2\. dex2oat內聯優化(dex不可見優化)
ART(Android Runtime)是Android在4.4版本中引入的新虛擬機環境,在5.0版本正式取代了Dalvik VM。ART環境下,App安裝時其包含的Dex文件將被dex2oat預編譯成目標平臺的機器碼oat,從而提高了App的運行效率。在這個預編譯過程中,dex2oat對目標代碼的優化過程與Dalvik VM下的dexopt有較大區別,尤其是在5.0版本以后ART環境下新增的方法內聯優化,改變了原本的方法分布和調用流程。優化dex2oat時方法內聯優化的條件
dex2oat時,方法被內聯優化的條件是實現在ART的源碼中的,每個android版本都有一些明顯的差異區別。內聯優化特性是從kOptimizing Compiler引入的,最早出現在android 6.x,但是android 6.x默認使用的是kQuick Compiler。而到了android 7.x,kOptimizing Compiler成了默認的Compiler類型。對于Optimizing Compiler,當以下條件均滿足時被調用的方法將被inline(僅針對Android N版本):
* App不是Debug版本的;
* 被調用的方法所在的類與調用者所在的類位于同一個Dex;(注意,符合Class N命名規則的多個Dex要看成同一個Dex)
* 被調用的方法的字節碼條數不超過dex2oat通過--inline-max-code-units指定的值,6.x默認為100,7.x默認為32;
* 被調用的方法不含try塊;
* 被調用的方法不含非法字節碼;
* 被調用方法還不能包含對接口方法的調用。
此外,Optimizing Compiler的方法內聯可以跨多級方法調用進行,若有這樣的調用鏈:method1->method2->method3->method4,則在四個方法都滿足內聯條件的情況下,最終內聯的結果將是method1包含method2,method3,method4的代碼,method2包含method3,method4的代碼,以此類推。但這種跨調用鏈內聯會受到調用dex2oat時通過--inline-depth-limit參數指定的值的限制,默認為5,即超過5層的調用就不會再被內聯到當前方法了。
##### 3\. JIT內聯優化(dex不可見優化)
ART也包含一個具備代碼分析功能的即時 (JIT) 編譯器,該編譯器可以在 Android 應用運行時持續提高其性能。JIT 會利用運行時類型信息,可以更高效地進行內聯,并可讓堆棧替換 (OSR) 編譯成為可能。有些小伙伴對方法內聯有個印象是頻繁被調用的方法會發生內聯,這一塊工作就是JIT在運行時完成的。
- Android
- 四大組件
- Activity
- Fragment
- Service
- 序列化
- Handler
- Hander介紹
- MessageQueue詳細
- 啟動流程
- 系統啟動流程
- 應用啟動流程
- Activity啟動流程
- View
- view繪制
- view事件傳遞
- choreographer
- LayoutInflater
- UI渲染概念
- Binder
- Binder原理
- Binder最大數據
- Binder小結
- Android組件
- ListView原理
- RecyclerView原理
- SharePreferences
- AsyncTask
- Sqlite
- SQLCipher加密
- 遷移與修復
- Sqlite內核
- Sqlite優化v2
- sqlite索引
- sqlite之wal
- sqlite之鎖機制
- 網絡
- 基礎
- TCP
- HTTP
- HTTP1.1
- HTTP2.0
- HTTPS
- HTTP3.0
- HTTP進化圖
- HTTP小結
- 實踐
- 網絡優化
- Json
- ProtoBuffer
- 斷點續傳
- 性能
- 卡頓
- 卡頓監控
- ANR
- ANR監控
- 內存
- 內存問題與優化
- 圖片內存優化
- 線下內存監控
- 線上內存監控
- 啟動優化
- 死鎖監控
- 崩潰監控
- 包體積優化
- UI渲染優化
- UI常規優化
- I/O監控
- 電量監控
- 第三方框架
- 網絡框架
- Volley
- Okhttp
- 網絡框架n問
- OkHttp原理N問
- 設計模式
- EventBus
- Rxjava
- 圖片
- ImageWoker
- Gilde的優化
- APT
- 依賴注入
- APT
- ARouter
- ButterKnife
- MMKV
- Jetpack
- 協程
- MVI
- Startup
- DataBinder
- 黑科技
- hook
- 運行期Java-hook技術
- 編譯期hook
- ASM
- Transform增量編譯
- 運行期Native-hook技術
- 熱修復
- 插件化
- AAB
- Shadow
- 虛擬機
- 其他
- UI自動化
- JavaParser
- Android Line
- 編譯
- 疑難雜癥
- Android11滑動異常
- 方案
- 工業化
- 模塊化
- 隱私合規
- 動態化
- 項目管理
- 業務啟動優化
- 業務架構設計
- 性能優化case
- 性能優化-排查思路
- 性能優化-現有方案
- 登錄
- 搜索
- C++
- NDK入門
- 跨平臺
- H5
- Flutter
- Flutter 性能優化
- 數據跨平臺