JAVA性能優化權威指南 讀書筆記四

HotSpot JIT編譯器

簡介

  編譯指的是從編程完成的代碼轉化到機器能夠是使用的機器碼的過程,在這個過程中開發人員可能需要等待很長一段時間才能得到最終可以運行的軟件。JAVA採用了另外一種角度來解決這個問題,由於JAVA是基於JVM虛擬機的一種語言,這就使得java可以將編譯的過程分爲兩個步驟。先將代碼編譯成虛擬機JVM能夠看懂的部分(class),然後再由虛擬機進行動態的將應用執行的class代碼動態的轉換爲機器碼並最終執行。

  由於這個編譯分開的步驟,所以java才真正意義上擁有了一次編譯到處運行的優勢和特點,因爲詳細的本地機器碼翻譯被下放到各個不同環境的JVM中去了,在代碼以及初次編譯的時候開發人員就不用考慮這個問題。

 

類繼承關係分析

  由於在java中類的關係比較複雜,特別是涉及到方法覆蓋和重載,優化的過程就會變得比較麻煩,所以在jvm中使用了CHA類型繼承關係分析,其基礎的思想是隻考慮已經加載的子類,並將信息記錄在編譯代碼中,如果執行的過程中有後續的代碼覆蓋其中的方法時,之前的優化會被丟棄,JVM使用逆優化來解決這個問題。

 

編譯策略

  之前有論述將java的編譯過程分爲兩個部分,但是JVM那個部分是在運行的時候纔會發生,畢竟JVMjava程序需要運行的時候纔會用到的東西,以下的情況也就順理成章了:JIT沒有時間編譯所有方法,所有代碼最初都是在解釋器中運行。

  但如果全部都是用解釋執行,那麼效率將會成爲一個很大的問題,所以在JVM中採取了這樣的機制:一旦方法被調用的次數比較多,那麼這個方法就能得到編譯。

  具體的執行通過兩個方法的計數器方法調用計數器以及回邊計數器來完成,方法調用計數器每次調用方法值加一,回邊計數器每次代碼從後跳轉至前加一(循環等步驟)。超過JVM設置的閥值那麼這個方法就會得到編譯。

  一般的過程是這樣的,解釋器通知JIT編譯器執行編譯,但是另一方面解釋器繼續執行代碼,直到編譯完成之後編譯代碼會自動關聯方法,當然這個部分也可以通過改變JVM中的參數值進行設置。

  當長時間的java循環的時候JVM會使用棧上替換的方法,這個操作的關鍵就是不直接編譯方法,而是編譯解釋器幀,通過直接編譯解釋器幀的代碼使得在循環過程中也能夠充分利用編譯的成果。

 

逆優化

    JVM中還對於編譯以及運行有更高的容錯機制,那就是逆優化。就是將編譯幀轉換爲解釋器的解釋幀,這個能將編譯過程中的某些樂觀優化退回,同時這個過程允許了在編譯過程中出現的更大更激進的樂觀優化。並且由於在HotSpot中採用方法活躍性的分析法,將逆優化的內存成本極大的降低。

 

Client JIT編譯器以及Server JIT編譯器

      Client JIT編譯器的目標是更快的啓動以及快速編譯,早期的Client JIT編譯器就是一個簡單快捷的代碼生成器,在1.4開始支持非那個發內聯,到了1.6有了比較大的改動,基本就是性能提高構架改動等。

      Server JIT編譯器目標是在應用的穩定運行的時間範圍內,將應用的性能推向極致,編譯的時候優化幅度大,但是這同樣帶來了編譯成本的提高。

Server JIT編譯器的中間代碼IR,是一個基於SSAIR,使用不同的方式展現控制流--程序依賴圖。這種方式企圖捕獲每次執行過程中的最小約束,將其反饋給優化器做出比較大幅度的優化計算。

  所有基於JAVA字節碼的JIT編譯器都需要處理卸載或未初始化的類,Server採用的方式是停止解析並生成罕見陷阱,請求逆優化,然後在下一次編譯觸發的時候重新編譯。

      Server JIT對於代碼的循環做了大量的優化,循環判斷外堤、循環展開、迭代分離。迭代分離將循環轉換成3個部分:預循環、主循環、後循環,將主循環所需要的邊界判斷消除,並直接展開主循環。超字,循環向量化的方式,如循環在內存操作上是線性的,就可以合成一個矢量操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章