因爲不一樣的操做系統,相同程序編譯後的機器碼會不一樣,因此Java會使用JVM來屏蔽操做系統的差別,而在JVM上直接能夠運行的就是Java編譯後的字節碼(.class);前端
動態類型語言:指在運行期間纔去作數據類型檢查的語言,也就是說,在用動態類型的語言編程時,永遠也不用給任何變量指定數據類型,該語言會在你第一次賦值給變量時,在內部將數據類型記錄下來。java
靜態類型語言:靜態類型語言與動態類型語言恰好相反,它的數據類型是在編譯其間檢查的,也就是說在寫程序時要聲明全部變量的數據類型。編程
對於動態語言與靜態語言的區分,套用一句流行的話就是:Static typing when possible, dynamic typing when needed。後端
綜上所述,Java是屬於靜態語言,由於在編譯階段就要肯定全部變量的數據類型。然而Java編譯後並非機器碼,而是JVM解釋執行的字節碼。因此,其稍微有些動態語言的特性:解釋執行。架構
JVM屏蔽不一樣操做系統的差別,JVM通過長期發展已足夠成熟和完善。一個完整的語言包括:前端、優化、後端、runtime、庫。函數
Java程序最初是僅僅經過解釋器解釋執行的,即對字節碼逐條解釋執行,這種方式的執行速度相對會比較慢,尤爲當某個方法或代碼塊運行的特別頻繁時,這種方式的執行效率就顯得很低。優化
因而後來在虛擬機中引入了JIT編譯器(即時編譯器),當虛擬機發現某個方法或代碼塊運行特別頻繁時,就會把這些代碼認定爲「Hot Spot Code」(熱點代碼),爲了提升熱點代碼的執行效率,在運行時,虛擬機將會把這些代碼編譯成與本地平臺相關的機器碼,並進行各層次的優化,完成這項任務的正是JIT編譯器。操作系統
運行過程當中會被即時編譯器編譯的「熱點代碼」有兩類:線程
- 被屢次調用的方法。
- 被屢次調用的循環體
兩種狀況,編譯器都是以整個方法做爲編譯對象,這種編譯也是虛擬機中標準的編譯方式。要知道一段代碼或方法是否是熱點代碼,是否是須要觸發即時編譯,須要進行Hot Spot Detection(熱點探測)。目前主要的熱點斷定方式有如下兩種:cdn
基於採樣的熱點探測:採用這種方法的虛擬機會週期性地檢查各個線程的棧頂,若是發現某些方法常常出如今棧頂,那這段方法代碼就是「熱點代碼」。這種探測方法的好處是實現簡單高效,還能夠很容易地獲取方法調用關係,缺點是很難精確地確認一個方法的熱度,容易由於受到線程阻塞或別的外界因素的影響而擾亂熱點探測。
基於計數器的熱點探測:採用這種方法的虛擬機會爲每一個方法,甚至是代碼塊創建計數器,統計方法的執行次數,若是執行次數超過必定的閥值,就認爲它是「熱點方法」。這種統計方法實現複雜一些,須要爲每一個方法創建並維護計數器,並且不能直接獲取到方法的調用關係,可是它的統計結果相對更加精確嚴謹。
JVM主要分爲類加載器、執行引擎、運行時數據區域;
JVM運行時數據區域:方法區、Java堆、Java棧、本地方法棧;
線性共享:方法區、Java堆; 線程私有:Java棧、本地方法棧;
如今主流的商用虛擬機(如Sun HotSpot、IBM J9)中幾乎都同時包含解釋器和編譯器(三大商用虛擬機之一的JRockit是個例外,它內部沒有解釋器,所以會有啓動相應時間長之類的缺點,但它主要是面向服務端的應用,這類應用通常不會重點關注啓動時間)。兩者各有優點:當程序須要迅速啓動和執行時,解釋器能夠首先發揮做用,省去編譯的時間,當即執行;當程序運行後,隨着時間的推移,編譯器逐漸會返回做用,把愈來愈多的代碼編譯成本地代碼後,能夠獲取更高的執行效率。解釋執行能夠節約內存,而編譯執行能夠提高效率。
HotSpot虛擬機中內置了 兩個JIT編譯器:Client Complier和Server Complier,分別用在客戶端和服務端,目前主流的HotSpot虛擬機中默認是採用解釋器與其中一個編譯器直接配合的方式工做。