記憶體模型
記憶體模型如下圖所示
堆
堆是Java虛擬機器所管理的記憶體最大一塊。堆是所有執行緒共享的一塊記憶體區域,在虛擬機器啟動時建立。此記憶體區域唯一的目的就是存放物件例項。所有的物件例項都在這裡分配記憶體
Java堆是垃圾收集器管理的主要區域。從記憶體回收的角度來看,由於現在的垃圾收集器採用的是分代收集演算法。所以,java堆又分為新生代
和老年代
。從記憶體分配的角度來說,執行緒共享的java對中可能劃分出多個執行緒私有的fenp緩衝區(Thread Local Allocation Buffer)。
可以通過 -Xms
、-Xmx
分別控制堆初始化是最小堆記憶體和最大堆記憶體大小。
虛擬機器棧
與程式計數器一樣,java虛擬機器棧也是執行緒私有的,他的生命週期與執行緒相同。
虛擬機器棧描述的是Java方法的執行的記憶體模型:每個方法在執行的同時會建立一個棧楨(stack frame)
用於儲存區域性變數表、運算元棧、動態連結串列、方法出口等資訊
。每個方法從呼叫直至執行完成的過程,就對應著棧楨在虛擬機器棧中入棧到出棧的過程。
虛擬機器棧儲存的資料型別
- 區域性變數表
存放的是編譯器可知得到各種基本資料型別boolean、byte、char、short、int、float、long、double、物件引用(refrence型別,不等同於物件本身,一個指向物件的起始記憶體位置的引用指標)
- 運算元棧
- 動態連結串列
- 方法出口
...
常見異常
在虛擬機器規範中,對這個區域規定了兩種異常情況:
- 如果執行緒請求的棧深度大於虛擬機器所允許的深度,將丟擲
StackOverflowError
如果虛擬機器棧可以動態擴充套件,擴充套件時無法申請做夠的記憶體,將會爬出
OutOfMemorryError
本地方法棧
與虛擬機器棧發揮的作用非常類似,他們之間的區別是虛擬機器棧為虛擬機器執行java方法服務,而本地方法棧則為虛擬機器使用到的
native
方法服務。與虛擬機器棧一樣,本地房發展區域也會丟擲StackOverflowError
,OutOfMemorryError
異常。方法區(1.8後該區域被廢棄)
方法區與java堆一樣,是各個執行緒所共享的,它用來儲存已被虛擬機器載入的
類資訊
、常量
、靜態變數
、即時編譯後的程式碼
等資料。
方法區是jvm提出的規範,而永久代
就是方法區的具體實現。
java虛擬機器對方法區的限制非常寬鬆,可以像堆一樣不需要連續的記憶體可可選擇的固定大小外,還可以選擇不識閒垃圾收集,相對而言,垃圾收集行為在這邊區域是比較少出現的。
在方法區會報出 永久代記憶體溢位的錯誤。而java1.8為了解決這個問題,就提出了meta space(元空間)
的概念,就是為了解決永久代記憶體溢位的情況,一般來說,在不指定meta space
大小的情況下,虛擬機器方法區記憶體大小就是宿主主機的記憶體大小程式計數器
程式計數器是一塊較小的記憶體空間,他可以看做是當前執行緒所執行位元組碼的行號指示器。在虛擬機器的概念模型裡,位元組碼直譯器工作時就是通過改變這個計數器的值來選擇下一條將要執行的位元組碼指令。
由於JAVA虛擬機器的多執行緒是通過多執行緒流轉切換並分配處理器執行時間的方式來實現的。在任一一個確定的時刻,一個處理器都只會執行一條執行緒中的指令。因此,為了執行緒切換後能恢復到正確的執行位置,每條執行緒都需要一個獨立的程式計數器,各個執行緒的計數器之間互不影響,獨立儲存,我們稱該類記憶體區域為執行緒私有
如果執行緒正在執行一個Java方法,這個計數器記錄的是正在執行的虛擬機器位元組碼指令的地址。執行時常量池
執行時常量池是方法區的一部分。Class檔案除了 有類的版本、欄位、方法、介面等描述資訊外,還有一項是常量池,用於存放編譯期生成的各種字面量和符號引用,這部分內容在類載入後進入方法區的執行時常量池。
執行時常量池相對於Class檔案常量池的另外一個重要特徵是具備動態性
.Java語言並不要求常量一定只有在編譯器才能產生,依舊是並非預置入Class檔案中的常量池的內容才能進入方法區執行時常量池