JVM複習(晚期優化)
文章目錄
一,晚期(運行期)優化
1.三種編譯器
- 前端編譯器:直接把.java文件轉變成.class文件
- 後端運行期編譯器(JIT):把字節碼轉變成機器碼
- 靜態提前編譯器(AOT):直接把.java文件編譯成本地機器碼
2.編譯器和解釋器
2.1編譯器
編譯器是將字節碼編譯爲機器碼,並存入code cache,下次遇到相同的代碼直接執行,無需重複編譯(根據平臺類型 生成特定的機器碼)
2.2解釋器
解釋器是將字節碼解釋爲針對所有平臺都適用的機器碼,下次遇到相同的字節碼仍會執行重複的解釋
2.3聯繫
所以,當程序需要迅速啓動和執行的時候,解釋器可以首先發揮作用,省去編譯時間,立即執行;程序運行之後,隨着時間的推移,編譯器逐漸發揮作用,把越來越多的代碼編譯成本地代碼之後,可以獲取更高的執行效率,當程序運行環境中內存資源限制較大時,可以使用解釋執行節約內存,反之可以使用編譯執行來提升效率
3.編譯對象和觸發條件
在運行過程中會被即時編譯器編譯的是熱點代碼:
- 被多次執行的方法
- 被多次執行的循環體
如何判斷是否是熱點代碼
- 基於採樣的熱點探測
- 基於計數器的熱點探測
3.1基於採樣的熱點探測
採用這種方法的虛擬機會週期性的檢查各個線程的棧頂,如果發現某個方法經常出現在棧頂,那這個方法就是熱點方法,基於採樣的熱點探測的好處就是實現簡單,高效,還可以很容易的獲取方法調用關係,缺點就是很難精確的確認一個方法的熱度,容易因爲受到線程阻塞或者別的外界因素的影響而擾亂熱點探測
3.2基於計數器的熱點探測
採用這種方法虛擬機會爲每個方法建立計數器,統計方法的執行次數,如果執行次數超過一定閥值就認爲他是熱點方法
1.方法調用計數器
方法調用計數器統計方法被調用的次數
2.回邊計數器
統計一個方法中循環體代碼執行的次數,在字節碼中遇到向後跳轉的指令稱爲回邊
4.編譯優化技術
方法內聯
方法內聯的主要目的;
- 去除方法調用的成本(建立棧楨)
- 爲其他優化建立良好的基礎,方法內聯膨脹後,可以便於在更大範圍上採用後續的優化手段,從而獲取更好的優化效果
公共字表達式清除
如果一個表達式E已經計算過了,並且從先前的計算到現在E中所有變量的值都沒有發生變化,那麼E的這次出現就成爲了公共子表達式。對於這種表達式,沒有必要花時間再對它進行計算,只需要直接用前面計算過的表達式結果代替E就可以了
逃逸分析
逃逸分析的基本行爲就是分析對象動態作用域:當一個對象在方法中被定義後,他可能被外部方法所引用,例如作爲調用參數傳遞到其他方法中,稱爲方法逃逸。甚至還有可能被外部線程訪問到,譬如賦值給類變量或可以在其他線程中訪問的實例變量,稱爲線程逃逸
如果能證明一個對象不會逃逸到方法或線程之外,也就是別的方法或線程無法通過任何途徑訪問到這個對象,則可能爲這個變量進行一些高效的優化
-
棧上分配
如果確定一個對象不會逃逸出方法之外,那讓這個對象在棧上分配內存,對象分配的內存空間可以隨棧楨出棧而銷燬
-
同步消除
線程同步本身是一個相對耗時的過程,如果逃逸分析確定一個變量不會逃逸出線程,無法被其他線程訪問,那這個變量的肯定沒有讀寫競爭,對於這個變量可是實施同步消除
-
標量替換
如果逃逸分析證明一個對象不會被外部訪問,並且這個對象可以被拆散的話,那程序真正執行的時候將可能不創建這個對象,而改爲直接創建他的若干個被這個方法使用的成員變量來代替