1. 程式人生 > >一步一步學JVM-運行時數據區域

一步一步學JVM-運行時數據區域

count 運行期 存儲 編譯期 動態 局部變量表 編譯 表空間 機制

程序計數器(Program Counter Register)

像我們平時讀書一樣,當我們在去做別的事情之前,我們會對我們讀到什麽地方了做一個標記,方便我們再回來的時候接著重新讀。如果這本書有很多人讀呢?那麽每個人都會對自己讀到了哪裏做一個標記。(標記都是個人自己保存)

那麽程序計數器也是一樣的,同樣的代碼,可能會被多個線程執行,那麽每個線程都要記住自己執行到哪行代碼了。這樣在線程再次切換執行的時候,知道代碼接著從哪裏執行。

所以程序計數器是線程私有的,每個線程都會程序計數器。對於正在執行的Native方法,這個計數器值為空。

虛擬機棧(VM Stack)

與程序計數器一樣,Java虛擬機棧也是線程私有的。每個線程執行的時候都會創建一個棧幀(Stack Frame)。用來存放局部變量表、操作數棧、動態鏈接、方法出口等信息。每個方法的調用到執行完成的過程,都對應著一個棧幀在虛擬機中入棧到出棧的過程。

  局部變量表

局部變量表中存放了編譯器可知的各種數據類型,和對象引用類型。其中除了64位長度的long和double類型會占用2個局部變量空間(Slot),其余的數據類型只占用1個。所以每個方法需要分配多大的局部變量表空間是完全確定的,在編譯期間就完成分配。在方法運行期間不會發生改變。

本地方法棧(Native Method Stack)

與虛擬機棧一樣,只是虛擬機棧是為虛擬機執行的Java方法服務,而本地方法棧為虛擬機中使用到的Native方法服務。

Java堆,是被所有線程共享的區域,在虛擬機啟動時創建。用來存放對象示例。

  隨著對象的創建,Java堆中的對象實例會越來越多,會造成內存溢出。在這些對象中,有百分之八十都是使用完之後就不用了,所以我們可以對這些對象進行回收。就引出了垃圾回收機制,對堆中沒用的對象進行清理。為了方便對象清理,又把堆分為了新生代和老年代。其中新生代又可以詳細分為Eden區、From Survive區和To Survive區。

方法區

在方法區存儲了類的信息,靜態變量、常量等數據。雖然Java虛擬機規範把方法區描述為堆的一個邏輯部分,但是它有一個別名Non-Heap(非堆),目的是為了和Java堆區分開。

在HotSpot虛擬機上,方法區也被稱為“永久代”,這與Java虛擬機的垃圾回收有關。但是這樣設計並不好,更加容易導致內存溢出問題。HotSpot虛擬機現在也有放棄永久代並逐步改為采用Native Memory來實現方法區的規劃。從JDK1.7的HotSpot中,已經把原本在永久代的字符串常量池移出。

運行時常量池

運行時常量池也是方法區的一部分。用來存放編譯器生成的各種字面量和符號引用。Java語言並不要求常量池一定只有編譯器才能產生,運行期間也可能將新的常量放入池中。利用的最多的就是String的intern()方法。

直接內存

直接內存並不是虛擬機運行時數據區的一部分,也不是Java虛擬機規範中定義的內存區域。但是這部分內存被頻繁使用,也可能導致內存溢出異常出現。

一步一步學JVM-運行時數據區域