深入理解JVM之前端编译器(一)
前兩天在leetcode做了算法題,驚訝的發現用java實現的時間復雜度,竟然躋身于C/C++同列,甚至偶爾會超過后兩者,雖然知道JVM功不可沒,但還是很好奇在VM編譯過程中到底發生了什么,翻出《深入理解java虛擬機》一探究竟,算是有所收獲,記錄如下。
概述
java語言的“編譯期”其實是一段“不確定”的操作過程,因為可能是下面三種:
- 前端編譯器
叫編譯器的前端可能更合適,主要是把.java文件轉變成.class文件。主要種類有:Sun的Javac、Eclipse JDT的增量式編譯器(ECJ)。 - JIT編譯器
就是可能指虛擬機的后端運行期編譯器(JIT編譯器:Just In Time Compiler),把「字節碼」變成「機器碼」,主要有:Hotspot VM的C1、C2編譯器。 - AOT編譯器
上面兩個可能關心更多,這個是指用靜態提前編譯器(AOT編譯器:Ahead Of Time Compiler)直接把*.java變成本地機器碼的過程。
本文后面所指的編譯器和編譯期都表示第一種。
關于優化的兩點解釋:
也就是說java中即時編譯器的在運行期的優化對程序運行更重要,而前端編譯器在編譯期的優化對于程序編碼更重要。注意此處的「編譯期」和「運行期」、「程序編碼」和「程序運行」的區別。
Javac編譯器
Javac不像是Hotspot虛擬機本身是CPP(少量C)寫的,本身是java語言編寫的程序,這樣java程序員就很方便了解它的編譯過程了。關于源碼環境搭建和調試不做詳述,大致說下Javac的編譯過程,主要分為3個過程,分別是:
- 解析與填充符號表過程
- 插入式注解處理器的注解處理過程
- 分析與字節碼生成過程
Java語法糖
語法糖雖不能帶來實質性的功能的改進,但是它們或能提高效率,或能提升語法嚴謹性,或能減少編碼出錯機會。java中常見的語法糖如下:
泛型與泛型擦除
java的泛型規則只在程序源碼中存在,在編譯后就已經替換為原來的原生類型(RawType,裸類型),并且在相應的地方插入了強制轉換。
自動裝箱、拆箱與遍歷循環、變長參數
演示代碼如下(以下jdk環境1.8):
|
? 1 2 3 4 5 6 7 8 9 10 11 |
? public class AutoBoxCompile { public static void main(String[] args) { List<Integer> list =Arrays.asList(1,2,3,4); int sum=0; for (Integer i : list) { sum+=i; } System.out.println(sum); } } |
?
用的本地jd-gui.exe工具反編譯之后變成:
|
? 1 2 3 4 5 6 7 8 9 10 11 12 |
? public class AutoBoxCompile { public static void main(String[] args) { List list = Arrays.asList(new Integer[] { Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3), Integer.valueOf(4) }); int sum = 0; for (Integer i : list) { sum += i.intValue(); } System.out.println(sum); } } |
?
foreach明明是一顆語法糖特性,猜想是工具的問題,找了一個在線反編譯工具,得到下列代碼,可以發現變長參數、自動裝箱和遍歷循環的語法糖特性:
條件編譯
類似于下面這段if代碼,在編譯過程中就會被“運行”。
|
? 1 2 3 4 5 6 7 8 9 |
? public class Ifcompiler { public static void main(String[] args) { if (true) { System.out.println(1111); }else { System.out.println(2222); } } } |
?
生成的字節碼只包括System.out.println(1111);,將上述編譯之后產生的class反編譯如下圖:
只有使用條件為常量的if語句才能有上述效果,否則會被拒絕編譯比如while(false){};。
還有很多其他的語法糖,比如內部類、枚舉、斷言、switch以及try中關閉資源等等,有時間再去嘗試,重要的是明白語法糖是怎么回事。
最后
「之所以把從java文件到字節碼文件的編譯器叫做前段編譯器,是因為它只完成了從程序到抽象語法樹或者中間字節碼的轉變,而在此之后還有一組內置于虛擬機內部的“后端編譯器”完成了從字節碼到本地機器碼的過程,即前面提到的即時編譯器或JIT編譯器,這個編譯器的編譯速度及結果的優劣,是衡量虛擬機性能的很重要的指標。」
JVM還有很多的東西沒有去挖掘,希望這是個開端,能不斷的去探索java虛擬機更深處的東西。
from:http://zouzls.github.io/2016/09/06/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3JVM%E4%B9%8B%E5%89%8D%E7%AB%AF%E7%BC%96%E8%AF%91%E5%99%A8%EF%BC%88%E4%B8%80%EF%BC%89/?
總結
以上是生活随笔為你收集整理的深入理解JVM之前端编译器(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JIT编译器杂谈#1:JIT编译器的血缘
- 下一篇: 深入理解JVM之JIT编译器(二)