上面文章在介紹Java的內存模型的時候,提到過因爲編譯器的優化會致使重排序的問題,其中一個比較重要的點地方就是關於JIT編譯器的功能。JIT的英文單詞是Just In Time翻譯成中文就是及時,剛好的意思,意在說明JIT編譯器優化java的class文件裏面的byte code是拿捏的恰到好處。java
JIT編譯器是JRE裏面的一個爲了在運行時提高Java程序性能的一個重要組件,咱們知道Java代碼一大優點就是在於一次編寫,處處運行的特色。Java程序一般在編譯後是一大堆class文件,也就是咱們所說的字節碼,而後經過JVM來解釋執行這些與平臺無關的字節碼,從而屏蔽了操做系統的差別,作到了跨平臺的特色。但jvm在在運行時候執行class文件的字節碼的時候性能並無執行跟操做系統直接有關的機器指令性能來的快,正是由於這個緣由,纔出現JIT編譯器,目的就是爲了提升執行效率。緩存
到這裏,咱們再總結下JIT編譯器的定義:數據結構
==在Java程序運行時把一些class文件的字節碼給轉變成操做系統本地的指令碼,從而提高程序性能。==多線程
以下圖: app
在上面的圖咱們可以看到,咱們的java源文件先在編譯時被轉成class字節碼文件,而後在運行時會在當一個方法第一次調用時會被JIT再次編譯優化轉成native machine code也就是上面說的操做系統級別的指令。jvm
這裏面你們注意到僅僅當方法第一次調用時纔會進行JIT優化,那麼有個問題是既然JIT編譯器優化運行時執行性能,爲啥不把全部的方法都優化一次呢,而非得時用到的時候才優化呢? 這正是just in time寫照。 當JVM啓動時候,其實是會加載數千個方法的,理論上把全部方法都提早經過JIT轉換一下是會提高更多運行性能,但實際狀況是JIT編譯優化是須要耗費必定的cpu和內存資源(用來緩存指令),這也意味着若是直接優化全部方法,有可能致使jvm啓動的很是慢,即便它能在運行時帶來的必定的性能提高。性能
此外,JIT在運行時作編譯優化是須要從新理解字節碼的語義的,爲了分析方法,它的字節碼會被轉成一種叫作trace tree的數據結構,而後根據方法的trace tree來作相關分析和優化,最終字節碼會被轉成本地的機器碼。固然JIT會使用多線程來編譯task,從而使java應用程序也就是jvm啓動的更快。到這裏相信看了我上篇文章的同窗們,就會明白重排序的問題。學習
你看到的代碼順序,未必是其執行順序優化
這其實就是由於JIT在底層編譯優化的時候爲了提高編譯的性能,是會把字節碼放到多個線程裏面的執行的,固然這裏面必須保證單線程JIT優化不影響最終結果的邏輯,這就是後面會提到的關於 happend-before的約束。操作系統
最後咱們來看下JIT編譯優化的包括幾個方面:
(1)代碼內聯 (合併trace tree裏面小的方法)
(2)本地優化(本地分析和優化代碼的一小部分,一般使用靜態編譯器)
(3)控制流優化(從新排列控制流的代碼路徑進行優化)
(4)全局優化(對整個方法進行優化)
(5)本地字節碼生成(根據不一樣的操做系統,生成對應優化的本地機器碼)
總結:
本篇文章主要介紹了Java裏面JIT編譯器相關的內容,經過學習咱們應該認識到Java編譯的字節碼方法並不必定是直接就運行的,更多時候是會以 「延遲加載」 形式經過JIT優化,這樣把Java字節碼轉成本地的機器碼能更多的提高程序運行效率。