1. 程式人生 > >深入理解JVM(一)——執行時的資料區域

深入理解JVM(一)——執行時的資料區域

Java與C++的圍牆:記憶體動態分配,垃圾收集技術

程式計數器

當前執行緒所執行的位元組碼的行號指示器,通過改變這個計數器的值來選擇下一條執行的位元組碼指令,分支,迴圈,跳轉,異常處理,執行緒恢復等依賴計數器。

執行緒私有,唯一不會OutOfMemory的區域。

執行Java方法時指向正在執行的虛擬機器位元組碼,執行Native方法時為空。

Java虛擬機器棧

描述方法執行的記憶體模型,每個方法執行的同時會建立一個棧幀。用於儲存區域性變量表,運算元棧,動態連結,方法出口等資訊。

執行緒私有,生命週期與執行緒相同。

執行緒請求的棧深度大於虛擬機器允許的棧深度,StackOverFlowError;
虛擬機器棧可動態擴充套件,擴充套件時無法申請到足夠的記憶體,OutOfMemoryError。

區域性變數:編譯期可知的各種基本資料型別(boolean,byte,char,short,int,float,long,double),物件引用(reference型別,物件起始地址的指標,物件的控制代碼),returnAddress型別(位元組碼指令的地址)。
區域性變量表的大小及所需的記憶體空間在編譯器完成分配,執行期不會改變。其中64位的long和double佔用2個slot,其餘型別佔用一個。

本地方法棧

虛擬機器棧為虛擬機器執行的Java方法(也就是位元組碼)服務,本地方法棧指的是虛擬機器使用到的Native方法服務。虛擬機器規範中對本地方法棧使用的語言,方式和資料結構未做強制規定,虛擬機器可以自由實現。

也會有StackOverFlowError和OutOfMemoryError異常。

Java堆

記憶體中最大的一塊,所有執行緒共享。存放物件例項,幾乎所有的例項都在這裡分配記憶體。分為新生代和老年代,或者Eden空間,From Survivor空間,To Survivor空間。

Java虛擬機器規範:所有的物件例項以及陣列都要在堆上分配。

JIT的發展,逃逸分析技術的成熟,棧上分配,標量替換等優化技術使所有的物件例項以及陣列都要在堆上分配這一規範不那麼絕對。

方法區

(永久代-HotSpot)執行緒共享區域。

儲存已被虛擬機器載入的類資訊,常量,靜態變數,及時編譯器編譯後的程式碼等資料。GC的目標時是常量池和對型別的解除安裝。也會有OutOfMemoryError異常。

執行時常量池:方法區的一部分,Class檔案中除了有類的版本,欄位,方法,介面等資訊,還有常量池,用於存放編譯器生成的各種字面量和符號引用。

Java虛擬機器對Class檔案的每一部分都有嚴格規定,但對執行時的常量池沒有任何要求。

執行時的常量池具備動態性,不要求常量一定只在編譯器才能產生,執行期也可以。(String類的intern方法),也會有OutOfMemoryError異常。

intern 這個方法返回的是 返回字串物件的規範化表示形式,當呼叫 intern 方法時,如果池已經包含一個等於此 String 物件的字串(該物件由 equals(Object) 方法確定),則返回池中的字串。否則,將此 String 物件新增到池中,並且返回此 String 物件的引用。

直接記憶體

不是虛擬機器執行時記憶體區域。JDK1.4之後加入NIO,引入基於通道(channel)與快取區(buffer)的I/O方式,使用Native函式直接分配堆外記憶體,任何通過存在在Java堆中的物件引用進行操作。