1. 程式人生 > >Java執行時記憶體劃分

Java執行時記憶體劃分

這篇文章可以說是摘抄自周志明的《深入理解Java虛擬機器》,但是加上了自己的理解,印象可以更深些。

      Java虛擬機器在執行Java程式的時候會把他所管理的記憶體劃分為若干個不同的資料區域,各個區域有各自的用途,以及建立和銷燬的時間。有的區域隨著虛擬機器程序的啟動而存在,有的區域則依賴使用者執行緒的啟動和結束而建立和銷燬。

Java虛擬機器會把執行時的資料區域分為以下幾個區域:

程式計數器:

程式計數器是一塊很小的記憶體空間,代表著當前執行緒執行的位元組碼的行號指示器,記錄著所執行的行號,java虛擬機器執行的是由字尾名為.java的檔案編譯而來的.class檔案(位元組碼檔案),所以位元組碼直譯器根據程式計數器來執行位元組碼檔案。每個執行緒都有自己的程式直譯器,這樣才能保證程式的正確執行,也就是說程式計數器是執行緒私有的。

Java虛擬機器棧:

java虛擬機器棧是用來描述java方法的記憶體模型,每個方法在執行的同時都會建立一個棧幀,而這個棧幀儲存的是方法中的區域性變數,操作的資料,方法的入口返回值等資訊,當一個方法被呼叫的時候,就代表著棧幀的入棧直至方法的結束代表著棧幀的出棧。因為虛擬機器棧儲存的資料決定了他也是執行緒私有的,每個執行緒都擁有一個虛擬機器棧記錄著方法的內容。我們平時所說的棧就是指的是虛擬機器棧,其中儲存著基本資料型別和指向堆記憶體中物件的指標(物件的引用)。

本地方法棧:

這塊區域和虛擬機器棧執行的操作其實是一致的,但是他們之間的服務物件不一樣,虛擬機器棧為java方法服務,而本地方法棧為native方法服務,我們在看原始碼的時候經常了一看到用native關鍵字修飾的方法,這種方法的實現是用c/c++實現的,我們在平時是看不到他的原始碼實現的。

Java堆:

堆記憶體是這幾塊記憶體區域中最大的一塊,堆記憶體存在的目的是存放物件的例項(通過new建立的物件,物件的引用放在虛擬機器棧中指向堆中的例項),在虛擬機器啟動的時候堆記憶體也就被建立了,這塊記憶體被所有執行緒共享,在虛擬機器執行期間的所有執行緒建立的物件的例項都被儲存在堆記憶體中。既然堆被執行緒所共享,那麼執行緒建立的物件不能一直存放在這裡,總會有裝不下的時候,在一定條件下,java虛擬機器會觸發垃圾回收機制(GC),來回收這裡被看作沒有用的物件,虛擬機器所管理的垃圾回收器總是會對這塊區域進行管理操作。關於垃圾回收(GC)機制可以看另一篇文章:Java GC垃圾回收機制

方法區:

方法區和堆記憶體一樣,是各個執行緒共享的資料區域,看到這個方法區這個名字很快能想到這個區域存方法資訊,事實上方法區存放的資料很多,包括被虛擬機器載入的類資訊,用final修飾的常量,String物件,用static修飾的靜態變數。

執行時常量池:

準確的說這塊區域屬於方法區,也就受到了方法區的空間限制,之前所說的String物件,就是字串常量就是存放在這裡,編譯期生成各種字面值和符號引用,將在類價在後放入方法區的執行時常量池的。執行時常量池的儲存具有動態性,並不是在類載入時才能放入資料,在程式執行期間也可以有新的常量放入。String類中的intern()方法就是這種特點,詳看之前轉載的一篇文章:String的intern()方法詳解

直接記憶體:

這塊區域和java中的新的io方式(NIO)有關,不屬於虛擬機器的執行時資料區。NIO是一種基於通道,緩衝區的io方式。後面會詳細看看。

參考:《深入理解Java虛擬機器 JVM高階特性與最佳實踐》周志明