Java虛擬機(Java Virtual Machine 簡稱JVM)是運行所有Java程序的抽象計算機,是Java語言的運行環境,它是Java 最具吸引力的特性之一。
Java語言的一個非常重要的特點就是與平臺的無關性。而使用Java虛擬機是實現這一特點的關鍵。一般的高級語言如果要在不同的平臺上運行,至少需要編譯成不同的目標代碼。而引入Java語言虛擬機后,Java語言在不同平臺上運行時不需要重新編譯。Java語言使用模式Java虛擬機屏蔽了與具體平臺相關的信息,使得Java語言編譯程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就可以在多種平臺上不加修改地運行。Java虛擬機在執行字節碼時,把字節碼解釋成具體平臺上的機器指令執行。
一、java虛擬機的生命周期:Java虛擬機的生命周期 一個運行中的Java虛擬機有著一個清晰的任務:執行Java程序。程序開始執行時他才運行,程序結束時他就停止。你在同一臺機器上運行三個程序,就會有三個運行中的Java虛擬機。Java虛擬機總是開始于一個main()方法,這個方法必須是公有、返回void、直接受一個字符串數組。在程序執行時,你必須給Java虛擬機指明這個包換main()方法的類名。 Main()方法是程序的起點,他被執行的線程初始化為程序的初始線程。程序中其他的線程都由他來啟動。Java中的線程分為兩種:守護線程(daemon)和普通線程(non-daemon)。守護線程是Java虛擬機自己使用的線程,比如負責垃圾收集的線程就是一個守護線程。當然,你也可 以把自己的程序設置為守護線程。包含Main()方法的初始線程不是守護線程。只要Java虛擬機中還有普通的線程在執行,Java虛擬機就不會停止。如果有足夠的權限,你可以調用exit()方法終止程序。
二、java虛擬機的體系結構:每個Java虛擬機都有一個類裝載子系統,它根據給定的全限定名來裝入類型(類或接口)。同樣,每個Java虛擬機都有一個執行引擎,它負責執行那些包含在被裝載類的方法中的指令。
當JAVA虛擬機運行一個程序時,它需要內存來存儲許多東西,例如:字節碼、從已裝載的class文件中得到的其他信息、程序創建的對象、傳遞給方法的參數,返回值、局部變量等等。Java虛擬機把這些東西都組織到幾個“運行時數據區”中,以便于管理。
某些運行時數據區是由程序中所有線程共享的,還有一些則只能由一個線程擁有。每個Java虛擬機實例都有一個方法區以及一個堆,它們是由該虛擬機實例中所有的線程共享的。當虛擬機裝載一個class文件時,它會從這個class文件包含的二進制數據中解析類型信息。然后把這些類型信息放到方法區中。當程序運行時,虛擬機會把所有該程序在運行時創建的對象都放到堆中。
當每一個新線程被創建時,它都將得到它自己的PC寄存器(程序計數器)以及一個Java棧,如果線程正在執行的是一個Java方法(非本地方法),那么PC寄存器的值將總是指向下一條將被執行的指令,而它的Java棧則總是存儲該線程中Java方法調用的狀態——包括它的局部變量,被調用時傳進來的參數、返回值,以及運算的中間結果等等。而本地方法調用的狀態,則是以某種依賴于具體實現的方法存儲在本地方法棧中,也可能是在寄存器或者其他某些與特定實現相關的內存區中。
Java棧是由許多棧幀(stack frame)組成的,一個棧幀包含一個Java方法調用的狀態。當線程調用一個Java方法時,虛擬機壓入一個新的棧幀到該線程的Java棧中,當該方法返回時,這個棧幀被從Java棧中彈出并拋棄。
Java虛擬機沒有寄存器,其指令集使用Java棧來存儲中間數據。這樣設計的原因是為了保持Java虛擬機的指令集盡量緊湊、同時也便于Java虛擬機在那些只有很少通用寄存器的平臺上實現。另外,Java虛擬機這種基于棧的體系結構,也有助于運行時某些虛擬機實現的動態編譯器和即時編譯器的代碼優化。
三、類加載器子系統:Java虛擬機中的類加載器分為兩種:原始類加載器(primordialclassloader)和類加載器對象(classloader objects)。原始類加載器是Java虛擬機實現的一部分,類加載器對象是運行中的程序的一部分。不同類加載器加載的類被不同的命名空間所分割。類加載器調用了許多Java虛擬機中其他的部分和java.lang包中的很多類。比如,類加載對象就是java.lang.ClassLoader子類的實例,ClassLoader類中的方法可以訪問虛擬機中的類加載機制;每一個被Java虛擬機加載的類都會被表示為一個 java.lang.Class類的實例。像其他對象一樣,類加載器對象和Class對象都保存在堆中,被加載的信息被保存在方法區中。1、加載、連接、初始化(Loading,Linking and Initialization)類加載子系統不僅僅負責定位并加載類文件,他按照以下嚴格的步驟作了很多其他的事情:(具體的信息參見第七章的“類的生命周期”)1)、加載:尋找并導入指定類型(類和接口)的二進制信息2)、連接:進行驗證、準備和解析①驗證:確保導入類型的正確性②準備:為類型分配內存并初始化為默認值③解析:將字符引用解析為直接飲用3)、初始化:調用Java代碼,初始化類變量為合適的值2、原始類加載器(ThePrimordial Class Loader)每個Java虛擬機都必須實現一個原始類加載器,他能夠加載那些遵守類文件格式并且被信任的類。但是,Java虛擬機的規范并沒有定義如何加載類,這由Java虛擬機實現者自己決定。對于給定類型名的類型,原始萊加載器必須找到那個類型名加“.class”的文件并加載入虛擬機中。3、類加載器對象
雖然類加載器對象是Java程序的一部分,但是ClassLoader類中的三個方法可以訪問Java虛擬機中的類加載子系統。1)、protectedfinalClassdefineClass(…):使用這個方法可以出入一個字節數組,定義一個新的類型。2)、protectedClass findSystemClass(String name):加載指定的類,如果已經加載,就直接返回。3)、protectedfinalvoidresolveClass(Classc):defineClass()方法只是加載一個類,這個方法負責后續的動態連接和初始化。具體的信息,參見第八章“連接模型”( The Linking Model)。4、命名空間當多個類加載器加載了同一個類時,為了保證他們名字的唯一性,需要在類名前加上加載該類的類加載器的標識。