程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java代碼的高效執行

Java代碼的高效執行

編輯:關於JAVA
 

《Oracle JRockit: The Definitive Guide》一書是由Oracle JRockit的兩位資深開發人員寫的,其中的Marcus Hirt更是JRockit Mission Control的leader,這本書詳細的對Oracle JRockit進行了介紹,最突出的特點非常系統化的介紹了一個JVM通常是如何實現的,而JRockit這樣一個極為優秀的JVM又是做了哪些優化,為什麼做這些優化,這本書對於對JVM感興趣的同學而言應該是必讀的一本書,其實即使對於JVM興趣不強的同學,裡面的優化思路的介紹也是值得學習,本系列的blog主要是總結看這本書得到的一些收獲,由於書中知識量巨大,因此得分成多篇blog來總結了。

書的第二章為:Adaptive Code Generation,在這章中作者向我們講解了一個優秀的JVM是如何來實現代碼的高效執行的,感興趣的同學其實可以在不看下面blog內容之前,先考慮下如果是你做的話,你會怎麼做來實現Java代碼的高效執行呢,然後再對比下這章的內容,我想你能學到很多的,:)

用過Java的同學都知道,Java是通過javac將Java源碼編譯為class文件,然後通過ClassLoader裝載此class文件,之後就可執行此class了,要最高效的執行這個class,最好的方法莫過於class文件直接就是機器碼,這樣直接執行就可以了,但Java是跨平台的,因此class文件就不能是機器碼了。

由於class文件不是直接的機器碼,要執行它最簡單的方法就是采用純粹的解釋方式,解釋方式由於每次都得將class文件中的指令翻譯為對應的機器環境的指令,效率是很低的。

為了能更高效的執行,同時又保持跨平台的特性,另外一個方法就是在執行class時再將其翻譯為對應的機器碼,這個方法是比較靠譜的,因此無論是Hotspot、還是JRockit,都采用了這種方式,也就是大家熟知的JIT(Just In Time) Compiler。

OK,既然覺得在裝載class後翻譯成機器碼去執行可以比較高效,那這個時候又會出現兩種狀況,是執行class的時候就立刻翻譯成機器碼,還是先用解釋模式執行,然後到一定時機再翻譯成機器碼呢,之所以出現這兩種狀況,原因在於將class翻譯為機器碼是需要消耗時間的,因此如果執行class的時候就立刻翻譯成機器碼的話,也就會導致Java程序啟動速度會比較慢,JRockit是這麼認為的,JRockit的服務對象是server級應用,這類應用的特點是沒那麼在乎啟動速度,而更在乎的是執行時的高效,而且如果執行的時候就立刻翻譯成機器碼的話,就意味著壓根不需要實現解釋器,因此JRockit采取的方法是在執行class時直接編譯為機器碼,而Hotspot由於需要同時支持client和server應用,對於client應用而言,啟動速度非常重要,因此Hotspot采用的是先解釋執行,到了一定時機後再翻譯成機器碼。

如果認為就這樣就完成了Java代碼的執行的實現,那就太小看JVM了,由於JVM能夠知道代碼運行的全部狀況,自然還可以做出更多更出色的提升代碼執行速度的優化,例如標量替換、更好的inline等,後面再來細說,因此這樣就出現了一個狀況,什麼時候對哪些代碼來做這些更猛的優化呢。

真正值得做更猛的優化的代碼自然是所謂的”熱點”代碼,如何來發現哪些代碼是熱點代碼呢,通常有三種方法:
1、方法調用計數器
方法調用計數器是常見的方式,hotspot采用的即為這種,這種方式不好的地方就在於計數器本身經常是cpu cache misses的,因此稍微會有點影響性能。
2、對線程進行采樣
可采用軟件或硬件方式來實現,軟件方式實現不好的地方在於采樣的時候需要暫停線程,好處是因為是采樣,不需要對所有方法進行計數,硬件方式自然是最好的,但不是所有的硬件都支持的,支持的硬件中最典型的是intel IA-64的CPU。

在有了發現熱點代碼的方法後,接下來需要做的就是更猛的優化,有很多種,例如Java的代碼中,通常會是接口方式的調用,但因為是接口方式的調用,所以其實默認情況下是不好做inline處理的,但JVM為了更高效的執行代碼,如發現這代碼為熱點代碼,那麼就會做一些激進的優化,例如會假設這個接口只有一個實現,然後就可以直接將此實現對應的代碼inline進來了(至於為什麼inline後效率更高,這個請參考編譯原理之類的書),這些激進優化同樣適合於if、拋異常這些狀況,當然,當激進優化的條件失效時,就會逆優化回到之前基本編譯的代碼。
而其他的更猛的優化還包括根據線程執行路徑進行逃逸分析等,後面再專門寫一篇blog來講解下一些翻譯為機器碼的優化吧,其實大多都是編譯原理的一些東西。

書中在介紹JRockit如何實現自己的JIT Compiler時,提到了Bytecode混淆以及bytecode優化,JRockit的態度是bytecode混淆時將name進行混淆是靠譜的,但如果對control flow進行混淆,就不太好了,因為這有可能會導致jit compile時的有些優化也做不了了,而bytecode優化,JRockit的態度是應該避免,因為沒什麼太大的意義,更主要的優化還是得靠jit compiler。

JRockit的JIT Compiler的實現和Hotspot另外一個很大的不同在於JRockit並未采用on-stack replacement,據JRockit的研究,這個沒有太大必要,當然,對於編寫benchmark代碼時則要注意這個不同。

JIT Compiler在compile時還需要考慮的幾個重點問題:
1、為GC提供必要的信息;
2、為查錯提供必要的信息,例如代碼的行數、變量名等;

從這章的內容可以看到,JRockit為了能夠讓Java代碼能夠高效的執行,是做出了非常多的努力的,也可以看到很多JRockit與Hotspot不同的地方,甚至可以看出Java代碼的執行比C代碼的執行高效都是有可能的,:)。
 

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved