Java虛擬機(Java Virtual Machine),一種可以運行字節碼的虛擬機,將字節碼解釋成不一樣os下的機器指令,有了jvm,java語言在不一樣平臺上運行時不須要從新編譯,即平臺無關性。前端
原理:編譯後的 Java 程序指令並不直接在硬件系統的 CPU 上執行,而是由 JVM 執行。JVM屏蔽了與具體平臺相關的信息,使Java語言編譯程序只須要生成在JVM上運行的目標字節碼(.class),知足了高級語言要求的可移植性、可傳輸性、預編譯等等需求。java
一、以 Java 爲例,咱們在文本編譯器寫好了 Java 代碼,交由「編譯器」編譯成 Java Bytecode。而後 Bytecode 交由 JVM 來執行,這時候 JVM 充當了「解釋器」的角色,在解釋 Bytecode 成 Machine Code 的同時執行它,返回結果。 二、以 BASIC 語言(早期的能夠由計算機直譯的語言)爲例,經過文本編譯器編寫好,不用經歷「編譯」的過程,就能夠直接交由操做系統內部來進行「解釋」而後執行。 三、以 C 語言爲例,咱們在文本編譯器編寫好源代碼,而後運行 gcc hello.c 編譯出 hello.out 文件,該文件由一系列的機器指令組成的機器碼,能夠直接交由硬件來執行。
bootstrap
jvm.cfg
-server KNOWN
-client IGNORE
-hotspot ALIASED_TO -server
-classic WARN
-native ERROR
-green ERROR後端
KNOWN 表示存在 、IGNORE 表示不存在 、ALIASED_TO 表示給別的JVM去一個別名 WARN 表示不存在時找一個替代 、ERROR 表示不存在拋出異常性能優化
目前有不少語言選擇了jvm,好比說Scala,Kotlin,Ceylon,Xtend,Groovy,Clojure;
JVM通過長期的發展,已經足夠成熟和完備。一個完整的語言包括 前端、優化、後端、runtime、庫 JVM 把後面四個都給包辦了。數據結構
在Java虛擬機的規範中定義了一系列的子系統、內存區域、數據類型和使用指南。這些組件構成了Java虛擬機的內部結構,他們不只僅爲Java虛擬機的實現提供了清晰的內部結構,更是嚴格規定了Java虛擬機實現的外部行爲。架構
類加載器子系統:每個Java虛擬機都由一個類加載器子系統(class loader subsystem),負責加載程序中的類型(類和接口),並賦予惟一的名字。每個Java虛擬機都有一個執行引擎(execution engine)負責執行被加載類中包含的指令。jvm
程序的執行須要必定的內存空間,如字節碼、被加載類的其餘額外信息、程序中的對象、方法的參數、返回值、本地變量、處理的中間變量等等。Java虛擬機將 這些信息通通保存在數據區data areas中。雖然每一個Java虛擬機的實現中都包含數據區,可是Java虛擬機規範對數據區的規定卻很是的抽象。許多結構上的細節部分都留給了 Java虛擬機實現者本身發揮。不一樣Java虛擬機實現上的內存結構千差萬別。一部分實現可能佔用不少內存,而其餘如下可能只佔用不多的內存;一些實現可 能會使用虛擬內存,而其餘的則不使用。這種比較精煉的Java虛擬機內存規約,可使得Java虛擬機能夠在普遍的平臺上被實現。工具
數據區中的一部分是整個程序共有,其餘部分被單獨的線程控制。每個Java虛擬機都包含方法區(method area)和堆(heap),他們都被整個程序共享。Java虛擬機加載並解析一個類之後,將從類文件中解析出來的信息保存與方法區中。程序執行時建立的 對象都保存在堆中。 當一個線程被建立時,會被分配只屬於他本身的PC寄存器「pc register」(程序計數器)和Java堆棧(Java stack)。當線程不掉用本地方法時,PC寄存器中保存線程執行的下一條指令。Java堆棧保存了一個線程調用方法時的狀態,包括本地變量、調用方法的 參數、返回值、處理的中間變量。調用本地方法時的狀態保存在本地方法堆棧中(native method stacks),可能再寄存器或者其餘非平臺獨立的內存中。性能
Java堆棧有堆棧塊(stack frames (or frames))組成。堆棧塊包含Java方法調用的狀態。當一個線程調用一個方法時,Java虛擬機會將一個新的塊壓到Java堆棧中,當這個方法運行結束時,Java虛擬機會將對應的塊彈出並拋棄。
Java虛擬機不使用寄存器保存計算的中間結果,而是用Java堆棧在存放中間結果。這是的Java虛擬機的指令更緊湊,也更容易在一個沒有寄存器的設備上實現Java虛擬機。
解釋器咱們能夠理解爲,把一種高級語言轉換成另外一種語言的程序。在JVM中,解釋器即將字節碼文件轉成機器二進制語言,使咱們的電腦能夠直接執行。然而由於每次運行程序時都要先轉成另外一種語言再做運行,所以解釋器的運行速度可想而知,這也形成了java運行速度比較慢的印象。
從本質上講,每一個程序都是一臺機器的「描述」,而解釋器就是在「模擬」這臺機器的運轉,也就是在進行「計算」。因此從某種意義上講,解釋器就是計算的本質
解釋器通常都是「遞歸程序」。之因此是遞歸的緣由,在於它處理的數據結構(程序)自己是「遞歸定義」的結構。
在java1.2版本以後,現在的HotSpot VM中不只內置有解釋器,還內置有先進的JIT(Just In Time Compiler)編譯器,在Java虛擬機運行時,解釋器和即時編譯器可以相互協做,各自取長補短
HotSpot虛擬機採用了熱點代碼探測技術:經過計數器找出最具編譯價值的代碼,通知JIT以方法爲單位進行編譯。若是方法被頻繁調用,則觸發標準編譯;若是方法中循環次數不少,觸發棧上替換編譯動做。 HotSpot無需等待本地代碼輸出後才能執行程序,使得即時編譯壓力減少,有助於採用更更多的代碼優化技術。輸出高質量的操做系統本地代碼。
爲何HotSpot虛擬機要使用解釋器與編譯器並存的架構?
儘管並非全部的Java虛擬機都採用解釋器與編譯器並存的架構,但許多主流的商用虛擬機(如HotSpot),都同時包含解釋器和編譯器。解釋器與編譯器二者各有優點:當程序須要迅速啓動和執行的時候,解釋器能夠首先發揮做用,省去編譯的時間,當即執行。在程序運行後,隨着時間的推移,編譯器逐漸發揮做用,把愈來愈多的代碼編譯成本地代碼以後,能夠獲取更高的執行效率。當程序運行環境中內存資源限制較大(如部分嵌入式系統中),可使用解釋器執行節約內存,反之可使用編譯執行來提高效率。此外,若是編譯後出現「罕見陷阱」,能夠經過逆優化退回到解釋執行。
編譯的時間開銷
解釋器的執行,抽象的看是這樣的:
輸入的代碼 -> [ 解釋器 解釋執行 ] -> 執行結果
而要JIT編譯而後再執行的話,抽象的看則是:
輸入的代碼 -> [ 編譯器 編譯 ] -> 編譯後的代碼 -> [ 執行 ] -> 執行結果
說JIT比解釋快,其實說的是「執行編譯後的代碼」比「解釋器解釋執行」要快,並非說「編譯」這個動做比「解釋」這個動做快。 JIT編譯再怎麼快,至少也比解釋執行一次略慢一些,而要獲得最後的執行結果還得再通過一個「執行編譯後的代碼」的過程。 因此,對「只執行一次」的代碼而言,解釋執行其實老是比JIT編譯執行要快。 怎麼算是「只執行一次的代碼」呢?粗略說,下面兩個條件同時知足時就是嚴格的「只執行一次」
一、只被調用一次,例如類的構造器(class initializer,())
二、沒有循環
對只執行一次的代碼作JIT編譯再執行,能夠說是得不償失。 對只執行少許次數的代碼,JIT編譯帶來的執行速度的提高也未必能抵消掉最初編譯帶來的開銷。
只有對頻繁執行的代碼,JIT編譯才能保證有正面的收益。 編譯的空間開銷 對通常的Java方法而言,編譯後代碼的大小相對於字節碼的大小,膨脹比達到10x是很正常的。同上面說的時間開銷同樣,這裏的空間開銷也是,只有對執行頻繁的代碼才值得編譯,若是把全部代碼都編譯則會顯著增長代碼所佔空間,致使「代碼爆炸」。 這也就解釋了爲何有些JVM會選擇不老是作JIT編譯,而是選擇用解釋器+JIT編譯器的混合執行引擎。
爲什麼HotSpot虛擬機要實現兩個不一樣的即時編譯器?
HotSpot虛擬機中內置了兩個即時編譯器:Client Complier和Server Complier,簡稱爲C一、C2編譯器,分別用在客戶端和服務端。目前主流的HotSpot虛擬機中默認是採用解釋器與其中一個編譯器直接配合的方式工做。程序使用哪一個編譯器,取決於虛擬機運行的模式。HotSpot虛擬機會根據自身版本與宿主機器的硬件性能自動選擇運行模式。
用Client Complier獲取更高的編譯速度,用Server Complier 來獲取更好的編譯質量。爲何提供多個即時編譯器與爲何提供多個垃圾收集器相似,都是爲了適應不一樣的應用場景。
開發人員能夠經過以下命令顯式指定Java虛擬機在運行時到底使用哪種即時編譯器,以下所示:
-client:指定Java虛擬機運行在Client模式下,並使用C1編譯器;
-server:指定Java虛擬機運行在Server模式下,並使用C2編譯器。
複製代碼
wiki上總結的jvm產品 https://en.wikipedia.org/wiki/Comparison_of_Java_virtual_machines
字節碼轉義後能夠容易的看出,是如何加載了init方法和add方法。
iload_1 從局部變量0中裝載int類型值
iload_2 從局部變量0中裝載int類型值
iadd 執行int類型的加法
ireturn 從方法中返回int類型的數據
複製代碼
一、[討論] [HotSpot VM] JIT編譯以及執行native http://hllvm.group.iteye.com/group/topic/39806
二、JVM編譯器的編譯過程 http://blog.csdn.net/tingfeng96/article/details/52261219
三、JVM即時編譯(JIT) http://blog.csdn.net/sunxianghuang/article/details/52094859