圖一 Java虛擬機的內部體系結構
每個Java虛擬機實例都有一個方法區以及一個堆,它們是由該虛擬機實例中所有線程共享的。
當虛擬機裝載一個class文件時,它會從這個class文件包含的二進制數據中解析類型信息,然后把這些類型信息放到方法區中;
當程序運行時,虛擬機會把所有該程序在運行時創建的對象都放到堆中;
當每一個新線程被創建時,它都將得到它自己的PC寄存器(程序計數器)以及一個Java棧,如果線程正在執行的是一個java方法(非本地方法),那么PC寄存器的值將總是指示下一條將被執行的指令,而它的Java棧則總是存儲該線程中java方法調用的狀態—包括它的局部變量,被調用時傳進來的參數,它的返回值,以及運算的中間結果等等。而本地方法調用的狀態,則是以某種依賴與具體實現的方式存儲在本地方法棧中,也可能是在寄存器或者其他某些與特定實現相關的內存中。
Java棧由許多棧幀(stack frme)或者說幀(frame)組成,一個棧幀包含一個方法調用。當線程調用一個Java方法時,虛擬機壓入一個新的棧幀到該線程的java棧中,當該方法返回時,這個棧幀被從Java棧中彈出并拋棄。
Java虛擬機沒有寄存器,其指令集使用Java棧來存儲中間數據。
數據類型
Java虛擬機是通過某些數據類型來執行計算的,數據類型及其運算都是由java虛擬機規范嚴格定義的。數據類型可以分為兩種:基本類型和引用類型。基本類型的變量持有原始值,而引用類型的變量持有引用值。術語“引用值”指的是對某個對象的引用,而不是該對象本身,與此相對,原始值則是真正的原始數據。Java語言中的所有基本類型同樣也都是java虛擬機中的基本類型,但是boolean有點特別,雖然虛擬機也把boolean看做基本類型,但是指令集對boolean只有很有限的支持。當編譯器把java源碼編譯成字節碼時,它會用int或byte來表示boolean。設計boolean值的操作會使用int,boolean數組是當作byte數組來訪問的。但是在“堆”區中,它也可以被表示為位域。 類型 范圍 byte 8bit,帶符號,二進制補碼,[-2∧7,2∧7-1] short 16bit,帶符號,二進制補碼,[-2∧15,2∧15-1] int 32bit,帶符號,二進制補碼,[-2∧31,2∧31-1] long 64bit,帶符號,二進制補碼,[-2∧63,2∧63-1] char 16bit,不帶符號,Unicode字符,[0,2∧16-1] float 32bit,IEEE 754標準單精度浮點數 double 64bit,IEEE 754標準雙進度浮點數 returnAddress 同一方法中某操作碼的地址 reference 堆中對某對象的引用,或者是null
Java虛擬機中,最基本的數據單元就是字(word),它的大小是由每個虛擬機實現的設計者來決定的。字長必須足夠大,至少是一個字單元就足以持有byte、short、int、char、float、returnAddress、reference類型的值,而兩個字單元就足以持有long或者double類型的值。因此,虛擬機實現的設計者至少得選擇32位作為字長。
方法區
由于所有線程都共享方法區,因此它們對方法區數據的訪問必須被設計為線程安全的。
類型信息 對每個裝載的類型,虛擬機都會在方法區中存儲以下類型信息:
l 這個類型的全限定名
l 這個類型的直接超類的全限定名
l 這個類型是類類型還是接口類型
l 這個類型的訪問修飾符
l 任何直接超接口的全限定名的有序列表
除這些基本信息外,還需要如下信息:
l 該類型的常量池
l 字段信息
l 方法信息
l 除了常量以外的所有類變量
l 一個到類ClassLoader的引用
一個到Class類的引用