學習Java不可避免的要學習Java虛擬機器,也就是JVM,Java虛擬機器規範裡面規定了程式執行期間會使用到的執行時資料區,這也是JVM的記憶體區域劃分的模型,應該可以這麼理解吧。
這其中有一些是隨著虛擬機器的啟動和退出而建立和銷燬的,這些區域是執行緒共享的,另外有一些是跟各個執行緒繫結的,隨著執行緒的開始和結束而建立和銷燬,我們可以稱這些區域是執行緒私有的。
根據《Java虛擬機器規範Java SE 7版》和《Java虛擬機器規範Java SE 8版》的規定,我們可以劃分出如下幾個執行時資料區,如下圖所示:
Java堆
在Java虛擬機器中,堆是可供各個執行緒共享的執行時記憶體區域,也是供所有類例項和陣列物件分配記憶體的區域。這塊區域隨著虛擬機器的啟動而建立,它的唯一使命就是存放物件例項,這塊區域也是GC主要關注的地方。
下面的就是我的筆記本上的JVM堆的劃分情況,可以看到分為新生代、老年代和永久代,新生代裡面有可以分為Eden Space、From Survivor Space和To Survivor Space。
Heap Usage:
PS Young Generation
Eden Space:
capacity = 17301504 (16.5MB)
used = 2483088 (2.3680572509765625MB)
free = 14818416 (14.131942749023438MB)
14.351862127130682% used
From Space:
capacity = 2621440 (2.5MB)
used = 2615312 (2.4941558837890625MB)
free = 6128 (0.0058441162109375MB)
99.7662353515625% used
To Space:
capacity = 6291456 (6.0MB)
used = 0 (0.0MB)
free = 6291456 (6.0MB)
0.0% used
PS Old Generation
capacity = 44564480 (42.5MB)
used = 13316368 (12.699478149414062MB)
free = 31248112 (29.800521850585938MB)
29.88112505744485% used
PS Perm Generation
capacity = 22020096 (21.0MB)
used = 14907008 (14.2164306640625MB)
free = 7113088 (6.7835693359375MB)
67.6972888764881% used
複製程式碼
根據虛擬機器規範的規定,Java堆可以是固定的大小也可以是按照需求動態擴充套件的,而且不需要保證是連續的。
存放內容: 所有的物件例項和陣列。
方法區
方法區是一個執行緒共享的區域,它用於儲存已被虛擬機器載入的類資訊、常量、靜態變數。方法區是堆的邏輯組成部分,Hotspot用永久代實現了方法區。 方法區還包含執行時常量池(JDK1.7以後移到堆中),用於存放編譯時生成的各種字面量和符號引用,但是不要求常量一定是在編譯時期產生的,執行期間也可以將新的常量放入池中,比如String的intern()方法便是利用了這一特性。
存放內容: 類的結構資訊,如類的欄位、方法、介面、建構函式,還有執行時常量池等。
程式計數暫存器
這塊區域是每個執行緒獨立擁有的,也就是執行緒私有的,我們可以把它看作是當前執行緒所執行的位元組碼的行號指示器。
這塊區域時虛擬機器規範裡面唯一一個沒有規定任何OutOfMemoryError情況的區域。
存放內容: 如果執行緒執行的是一個Java方法,那麼暫存器裡面記錄的就是正在執行的虛擬機器位元組碼指令的地址,如果執行緒執行的是一個native方法,那麼暫存器記錄的值為undefined。
虛擬機器棧
虛擬機器棧也是執行緒私有的記憶體區域。每個方法在執行的時候都會建立一個棧幀用於儲存區域性變數表、運算元棧、方法出口等資訊,每一個方法從呼叫到執行完成就是一個棧幀入棧和出棧的過程。
區域性變數表存放了編譯時期可知的各種基本資料型別、物件引用和指向了一條位元組碼指令的地址。
存放內容: 區域性變數表、運算元棧、方法出口等資訊。
本地方法棧
和虛擬機器棧類似,儲存Native方法的相關資訊。
存放內容: 區域性變數表、運算元棧、方法出口等資訊。