JAVA虛擬機器的生命週期
一個運行時的Java虛擬機器執行個體的天職是:負責運行一個java程式。當啟動一個Java程式時,一個虛擬機器執行個體也就誕生了。當該程式關閉退出,這個虛擬機器執行個體也就隨之消亡。如果同一台電腦上同時運行三個Java程式,將得到三個Java虛擬機器執行個體。每個Java程式都運行於它自己的Java虛擬機器執行個體中。
Java虛擬機器執行個體通過調用某個初始類的main()方法來運行一個Java程式。而這個main()方法必須是共有的(public)、靜態(static)、傳回值為void,並且接受一個字串數組作為參數。任何擁有這樣一個main()方法的類都可以作為Java程式啟動並執行起點。
public class Test { public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("Hello World"); }}
在上面的例子中,Java程式初始類中的main()方法,將作為該程式初始線程的起點,任何其他的線程都是由這個初始線程啟動的。
在Java虛擬機器內部有兩種線程:守護線程和非守護線程。守護線程通常是由虛擬機器自己使用的,比如執行垃圾收集任務的線程。但是,Java程式也可以把它建立的任何線程標記為守護線程。而Java程式中的初始線程——就是開始於main()的那個,是非守護線程。
只要還有任何非守護線程在運行,那麼這個Java程式也在繼續運行。當該程式中所有的非守護線程都終止時,虛擬機器執行個體將自動結束。假若安全管理器允許,程式本身也能夠通過調用Runtime類或者System類的exit()方法來退出。
JAVA虛擬機器的體繫結構
是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虛擬機器為每一個線程建立的記憶體區,這些記憶體地區是私人的,任何線程都不能訪問另一個線程的PC寄存器或者Java棧。