Java編譯期優化與運行期優化技術淺析


Java語言的“編譯期”是一段不確定的過程,因為它可能指的是前端編譯器把java文件轉變成class字節碼文件的過程,也可能指的是虛擬機后端運行期間編譯器(JIT)把字節碼轉變成機器碼的過程。
下面討論的編譯期優化指的是javac編譯器將java文件轉化為字節碼的過程,而運行期間優化指的是JIT編譯器所做的優化。
編譯期優化
虛擬機設計團隊把對性能的優化集中到了后端的即時編譯器(JIT)中,這樣可以讓那些不是由javac編譯器產生的class文件也同樣能享受到編譯器優化所帶來的好處。但是javac做了許多針對編碼過程的優化措施來改善程序員的編碼風格和提高編碼效率。許多新生的java語法特性,都是靠編譯器的“語法糖”來實現,而不是依賴虛擬機的底層改進來支持。
所以說,java中即時編譯器在運行期間的優化過程對於程序的運行來說更重要,而前端編譯器在編譯期的優化過程對於程序編碼來說關系更加密切。
javac編譯器的編譯過程大致可分為三個步驟:
1.解析與填充符號表過程;
2.插入式注解處理器的注解處理過程;
3.語義分析與字節碼生成過程。
下面分別來介紹。
解析與填充符號表;
解析步驟包含了 詞法分析和語法分析兩個過程,首先詞法分析是將源代碼的字符流轉變成為標記集合(token),然后語法分析是根據token序列來構造抽象語法樹(一種用來描述程序代碼語法結構的樹狀表示方式)。完成詞法分析和語法分析之后,下一步是 填充符號表,符號表是由一組符號地址和符號信息構成的表格,符號表中所登記的信息在編譯的不同階段都要用到(比如語義分析中符號表所登記的內容將用於語義檢查和產生中間代碼,目標代碼生成階段當對符號名進行地址分配時,符號表是地址分配的依據)。
插入式注解處理器的注解處理過程:
插入式注解處理器可以看做是一組編譯器的插件,在這些插件里面,可以讀取、修改、添加抽象語法樹中的任意元素。如果這些插件在處理注解期間對語法樹進行了修改,那么編譯器將 回到解析及填充符號表的過程重新處理,直到所有的插入式注解處理器都沒有再對語法樹進行修改為止。
語義分析與字節碼生成過程:
語法分析之后,編譯器獲得了程序代碼的抽象語法樹表示,語法樹能夠表示結構正確的源程序的抽象,但是無法保證源程序是否符合邏輯,而語義分析主要是對結構上正確的源程序進行上下文有關性質的檢查。
1.標注檢查
    標注檢查步驟檢查的內容包括諸如變量使用前是否已被聲明、變量與賦值之間的數據類型是否能夠匹配,等等。還有一個重要的動作稱為常量折疊也在此階段完成。
2.數據及控制流分析
     數據及控制流分析是對程序上下文邏輯更進一步的驗證,它可以檢查出諸如程序局部變量在使用前是否有賦值、方法的每條路徑是否有返回值、是否所有的受查異常都被正確處理了等問題。
3.解語法糖
       語法糖是指在計算機語言中添加某種語法,這種語法對語言的功能並沒有影響,但是更方便程序員使用。java中的泛型,變長參數,自動拆箱與裝箱,條件編譯等就屬於語法糖,它們在編譯階段就被還原成簡單的語法結構(比如List<String>和List<Integer>在運行期間其實是同一個類)。
4.字節碼生成
此過程是javac編譯過程的最后一個階段,字節碼生成階段將之前各個步驟所生成的信息轉化成字節碼寫到磁盤中,另外還進行少量的代碼添加和轉換工作。
運行期優化
在部分商用虛擬機中,java程序最初是通過解釋器進行解釋執行的,當虛擬機發現某個方法或代碼塊運行特別頻繁,就會把這些代碼認定為“熱點代碼”,為了提高熱點代碼的執行效率,在運行時,虛擬機就會把這些代碼編譯成與本地平台 相關的機器碼,並進行各種層次的優化,完成這個任務的編譯器稱為即時編譯器或JIT編譯器。
即時編譯器並不是虛擬機必須的部分,但是即時編譯器編譯性能的好壞、代碼優化程度的高低確是衡量一款商用虛擬機優秀與否的最關鍵的指標之一。
眾多主流的虛擬機都同時包含解釋器和JIT編譯器,解釋器與JIT編譯器各有優勢:當程序需要迅速啟動和執行時,解釋器可以首先發揮作用,省去編譯的時間,立即執行。當程序運行后,隨着事件的推移,JIT編譯器逐漸發揮作用,把越來越多的代碼編譯成本地代碼之后,可以獲取更高的執行效率。
會被即時編譯器編譯的熱點代碼有兩類:
1.被多次調用的方法體;
2.被多次調用的循環體。
即時編譯器會以整個方法作為編譯對象,將其編譯成機器碼。這種編譯方式因為編譯發生在方法執行過程之中,因此被稱作棧上替換(OSR)。
判斷一段代碼是否是熱點代碼的方式(熱點探測)有兩種:
1.基於采樣的熱點探測:
此方法會周期性檢查各個線程的棧頂,如果發現某個或某些方法經常出現在棧頂,那么這個方法就是熱點方法。此方法的缺點是很難精確地確認一個方法的熱度,容易受到諸如線程阻塞等因素影響。
2.基於計數器的熱點探測:
此方法會為每個方法甚至是代碼塊建立計數器,統計方法的執行次數,如果執行次數超過一個閥值就認為它是熱點方法。
注:默認設置下,執行引擎並不會同步等待編譯請求完成,而是繼續進入解釋器按照解釋方式執行字節碼,直到提交的請求被編譯器編譯完成。當編譯工作完成之后,這個方法的調用入口地址就會被系統自動改寫成新的地址,下一次調用該方法時就會使用已編譯的版本。也就是說,在編譯器還未完成之前,執行引擎仍按照解釋方式繼續執行,而編譯動作則在后台的編譯線程中進行。
優化技術:
一般來說即時編譯器所產生的本地代碼會比javac產生的字節碼更優秀。即時編譯器采用了一系列的技術來優化代碼,比如公共子表達式消除,數組范圍內檢查消除,方法內聯,逃逸分析等。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM