Java語言的“編譯期”几缭,可能指的是一個前端編譯期,把*.java文件轉(zhuǎn)變?yōu)?*.class文件的過程揣苏;也可能是虛擬機(jī)的后端運行期編譯器(JIT)把字節(jié)碼轉(zhuǎn)變?yōu)闄C(jī)器碼的過程幔摸,還可能是指使用靜態(tài)編譯器(AOT編譯器,Ahead Of Time Compiler)直接把 java文件編譯成本地機(jī)器碼的過程沥寥。
編譯期很廣碍舍,我們這里討論即時編譯器,因為即使編譯器邑雅,以下簡稱JIT片橡,JIT在運行期的優(yōu)化過程對于程序的運行更加重要。
JIT簡介
Java程序最初是通過解釋器來解釋執(zhí)行的淮野,當(dāng)虛擬器發(fā)現(xiàn)某個方法或代碼塊的運行特別頻繁時捧书,就會把這些代碼認(rèn)定為“熱點代碼”,為了提高熱點代碼的執(zhí)行效率骤星,在運行時经瓷,虛擬機(jī)會把這些代碼編譯為機(jī)器碼,并進(jìn)行各種層次的優(yōu)化洞难,完成這個任務(wù)的編譯器成為即使編譯器(JIT)舆吮。
簡單說就是熱點代碼會被進(jìn)行優(yōu)化。
什么是熱點代碼队贱?
- 被多次調(diào)用的方法:方法調(diào)用的多了色冀,代碼執(zhí)行次數(shù)也多,成為熱點代碼很正常柱嫌。
- 被多次執(zhí)行的循環(huán)體:假如一個方法被調(diào)用的次數(shù)少呐伞,只有一次或兩次,但方法內(nèi)有個循環(huán)慎式,一旦涉及到循環(huán)伶氢,部分代碼執(zhí)行的次數(shù)肯定多,這些多次執(zhí)行的循環(huán)體內(nèi)代碼也被認(rèn)為“熱點代碼”
如何檢測熱點代碼瘪吏?
判斷一段代碼是不是熱點代碼癣防,是不是需要觸發(fā)JIT,這樣的行為成為熱點探測掌眠,主要方式有兩種蕾盯。
-
基于采樣的熱點探測:采樣,指把時間域或空間域的連續(xù)量轉(zhuǎn)化成離散量的過程蓝丙,也就是取一部分级遭,周期性的檢查線程的棧頂望拖,如果發(fā)現(xiàn)某些方法經(jīng)常出現(xiàn)在棧頂,即熱點方法挫鸽。
缺點:不夠精確说敏,容易受到線程阻塞或外界因素的影響
優(yōu)點:簡單,高效 -
基于計數(shù)的熱點探測(HotSpot虛擬器默認(rèn)):為每個方法甚至是代碼塊建立計數(shù)器丢郊,統(tǒng)計執(zhí)行次數(shù)盔沫,如果執(zhí)行次數(shù)超過一定閾值就認(rèn)為是熱點代碼。
缺點:實現(xiàn)麻煩
優(yōu)點:統(tǒng)計結(jié)果精確
HotSpot虛擬器為每個方法準(zhǔn)備了兩類計數(shù)器:方法調(diào)用計數(shù)器和回邊計數(shù)器枫匾,兩個計數(shù)器都有一定的閾值架诞,超過閾值就會觸發(fā)JIT.
-XX:CompileThreshold 可以設(shè)置閾值大小,Client 編譯器模式下干茉,閾值 默認(rèn)的值 1500谴忧,而 Server 編譯器模式下,閾值 默認(rèn)的值則是 10000角虫。
編譯器優(yōu)化
當(dāng)JVM編譯代碼時俏蛮,它會將匯編指令保存在代碼緩存,代碼緩存具有固定大小上遥,一旦它被填滿搏屑,JVM將不能編譯更多的代碼。
–XX:ReservedCodeCacheSize 選項去增加代碼緩存的大小粉楚。
查看編譯日志
JVM啟動時辣恋,-XX:+PrintCompilation,它會報告什么時候代碼緩存滿了模软,以及什么時候編譯停止了伟骨。
另外可以通過jstat來查看編譯器信息。
jstat -compile JVM進(jìn)程ID
? ~ jstat -compiler 56067
Compiled Failed Invalid Time FailedType FailedMethod
968 0 0 0.80 0
最后
Java語言編譯優(yōu)化包含很多內(nèi)容燃异,這次主要圍繞JIT即時編譯器周邊來說携狭,希望能幫助到大家。
參考
- 《深入理解JVM》
- 深入淺出 JIT 編譯器
- 什么是JIT