1. 概覽
1.1. 即時編譯器是Java虛擬機的核心
1.1.1. just-in-time compiler,簡稱JIT compiler
1.1.2. 即時編譯器會頻繁地使用暫存器
1.2. 編譯型語言
1.2.1. 程式是以二進制(編譯后的)代碼的形式發布的
1.2.1.1. 匯編代碼是針對特定CPU的
1.2.1.2. 兼容的CPU可以執行同一個二進制檔案
1.2.2. 如C++和Fortran
1.3. 解釋型語言
1.3.1. 同樣的程式源代碼就可以在任何CPU上運行
1.3.2. 如PHP和Perl
1.4. 中間地帶
1.4.1. 編譯為一種中間的低級語言
1.4.1.1. Java位元組碼
1.4.1.2. 由JVM進一步編譯成匯編語言
1.4.2. 利用了腳本語言的平臺獨立性和編譯型語言的原生性能
1.4.3. 在代碼執行時將其編譯為平臺相關的二進制代碼
1.4.3.1. 是“即時”的
1.5. 熱點編譯
1.5.1. 只有一小部分代碼會頻繁執行,應用程式的性能則主要取決于這些代碼執行的快慢
1.5.2. 關鍵代碼被稱為應用程式的熱點
1.5.2.1. 這部分代碼執行得越多,就說這部分代碼越熱
1.5.3. 只執行一次的代碼,解釋執行Java位元組碼會更快一點
1.5.4. 代碼是頻繁呼叫的方法或者迭代多次的回圈,編譯它就是值得的
2. 分層編譯
2.1. 現在所有JVM都在使用的技術
2.2. -XX:-TieredCompilation標志
2.2.1. 默認值是true
2.3. 兩種型別
2.3.1. client編譯器
2.3.1.1. C1編譯器1
2.3.2. server編譯器
2.3.2.1. C2編譯器2
2.4. 編譯代碼的時機
2.4.1. 基于程式會運行多長時間和程式的啟動時間有多重要
2.4.2. C1編譯器比C2編譯器更早開始編譯
2.4.3. 在代碼執行的開始階段,C1編譯器的速度更快
2.4.4. C2編譯器在等待時獲得了資訊,這些資訊讓C2編譯器能夠對編譯后的代碼進行更好的優化
3. 編譯器標志
3.1. 代碼快取
3.1.1. 一種設定了最大值的系統資源
3.1.2. 影響JVM可以運行的編譯后的代碼總量
3.1.3. 最大值
3.1.3.1. -XX:ReservedCodeCacheSize=N
3.1.3.2. 默認240 MB
3.1.4. 初始大小
3.1.4.1. -XX:InitialCodeCacheSize=N
3.1.4.2. 默認2496 KB
3.2. Java 11中
3.2.1. 非方法代碼(nonmethod code)
3.2.1.1. -XX:NonMethodCodeHeapSize=N
3.2.2. 性能分析代碼(profiled code)
3.2.2.1. -XX:ProfiledCodeHeapSize=N
3.2.3. 非性能分析代碼(nonprofiled code)
3.2.3.1. -XX:NonProfiledCodeHeapSize=N
3.3. 檢查編譯程序
3.3.1. 不是用來優化的,它不會提升應用程式的性能
3.3.2. -XX:+PrintCompilation標志
3.3.2.1. 默認為false
3.3.3. attributes欄位由5個字符構成,表示正在編譯的代碼狀態
3.3.3.1. %
3.3.3.1.1. 堆疊上替換(on-stack replacement,OSR)
3.3.3.2. s
3.3.3.2.1. 方法是同步的
3.3.3.3. !
3.3.3.3.1. 方法有例外處理器
3.3.3.4. b
3.3.3.4.1. 在阻塞模式下發生的編譯
3.3.3.5. n
3.3.3.5.1. 原生方法封裝時發生的編譯
4. 分層編譯級別
4.1. 如果沒有額外的CPU周期可用,你能做的就是盡量縮減應用程式的大小
4.2. C1編譯器有3個級別,所有總共有5個編譯級別
4.2.1. 0
4.2.1.1. 解釋代碼
4.2.2. 1
4.2.2.1. 簡單C1編譯代碼
4.2.3. 2
4.2.3.1. 受限C1編譯代碼
4.2.4. 3
4.2.4.1. 完全C1編譯代碼
4.2.5. 4
4.2.5.1. C2編譯代碼
4.3. C1編譯器得到代碼是如何使用的資訊之后,會利用這些資訊進行優化,然后才開始編譯
4.4. 如果C2編譯器佇列已滿,那么佇列中的方法會被取出,在級別2上編譯
4.5. 如果C1編譯器佇列已滿,那么計劃在級別3上編譯的方法在等待編譯的同時,可以進行級別4的編譯
4.5.1. 它會被快速編譯到級別2,然后轉到級別4
4.6. 不重要的方法可以從級別2或者級別3開始編譯
4.6.1. 它們本質上不那么重要,所以會回到級別1
4.7. 如果代碼發生了逆優化,就會回到級別0
5. 逆優化(deoptimization)
5.1. 編譯器不得不“撤銷”之前的編譯
5.1.1. JVM替換之前編譯的代碼的程序
5.2. 發生情況
5.2.1. 代碼被丟棄(made not entrant)
5.2.2. 產生僵尸代碼(made zombie)
5.3. 代碼被丟棄的原因
5.3.1. 類和介面的作業方式
5.3.1.1. 逆優化對性能并沒有太大影響
5.3.2. 分層編譯的作業方式
5.3.2.1. 當代碼被C2編譯器編譯時,JVM必須替換已經被C1編譯器編譯的代碼
5.3.2.2. 它將舊代碼標記為丟棄,并用逆優化機制替換為新編譯的(更高效的)代碼
5.3.2.3. 讓代碼變得更快
5.4. 逆優化僵尸代碼
5.4.1. 僵尸代碼的小規模重新編譯,不會對大多數應用程式產生顯著的影響
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/545532.html
標籤:Java