【jvm】記憶體區域
jvm在執行的過程中會把它所管理的記憶體劃分為若干個不同的資料區域,這些資料區域中,有些依賴著使用者執行緒的啟動和結束而建立和銷燬,有些則隨著jvm程式的啟動而建立
記憶體區域
jvm的執行資料區域可以分為兩種:執行緒私有和執行緒共享
執行緒私有: 每個執行緒的私有資料,包括: 程式計數器、java虛擬機器器棧、本地方法棧
執行緒共享: 所有執行緒共享的部分,包括: Java 堆、方法區、常量池
jvm記憶體區域劃圖示
執行時資料區域
程式計數器
程式計數器是較小的記憶體空間,它可以看做是當前執行緒所執行的位元組碼的行號指示器,用來執行選取小一條需要執行的位元組碼指令,屬於執行緒私有的記憶體
如果執行的是一個java方法,這個計數器記錄的是正在執行的虛擬機器器位元組碼指令地址,如果執行的是Native方法,這個計數器值為空
虛擬機器器棧
虛擬機器器棧,也是執行緒私有的,它的生命週期與執行緒相同,每個方法在執行時都建立一個棧幀,每個方法從呼叫到執行完成,對應著一個棧幀的入棧到出棧
虛擬機器器棧描述的是java方法執行的動態記憶體模型
棧幀儲存的資料包括: 區域性變量表,運算元棧,動態連結,方法出口等資訊
在虛擬機器器棧中,規定了兩種異常:
- 當棧呼叫深度大於JVM所允許的範圍,會丟擲StackOverflowError的錯誤
- 當虛擬機器器棧在擴充套件記憶體時無法申請到足夠的記憶體,會丟擲OutOfMemoryError異常
本地方法棧
執行緒私有,與虛擬機器器棧提供的功能類似,只不過執行的是本地方法,也就是用Native修飾的方法
堆
堆是被執行緒共享的一塊記憶體區域,隨著jvm的啟動而建立,用來存放物件例項和陣列
這塊區域也是GC進行垃圾回收的主要區域,當申請不到空間時會丟擲 OutOfMemoryError異常
堆可以細分為新生代和老年代,新生代用來存放存活時間較短的物件,老年代用來存放存活時間較長的物件,新生代還可以細分為一個Eden區和兩個Survivor;
方法區
方法區也是被執行緒共享的一塊記憶體區域,用來存虛擬機器器中載入的類資訊,常量,靜態變數,即時編譯器編譯後的程式碼等資料
方法區是jvm的規範,而接下來要說的永久代和元空間正式jvm規範的一種實現
永久代(Permanent Space)
在jdk1.7時,方法區被叫做永久代(Permanent Space),由於方法區主要儲存類的相關資訊,所以對於動態生成類的情況比較容易出現永久代的記憶體溢位,當永久代出現記憶體溢位,會丟擲java.lang.OutOfMemoryError: PermGen space異常
元空間(MetaSpace)
在jdk1.8中移除了永久代,使用元空間代替,jdk1.7中,儲存在永久代的部分資料就已經轉移到了堆記憶體或者是直接記憶體。但永久代仍存在於jdk1.7中,並沒完全移除,譬如符號引用(Symbols)轉移到了直接記憶體;字面量(interned strings),類的靜態變數(class statics)轉移到了堆記憶體
元空間的本質和永久代類似,都是對JVM規範中方法區的實現。不過元空間與永久代之間最大的區別在於:元空間並不在虛擬機器器中,而是使用本地記憶體。因此,預設情況下,元空間的大小僅受本地記憶體限制,但可以通過以下引數來指定元空間的大小:
- -XX:MetaspaceSize,初始空間大小,達到該值就會觸發垃圾收集進行型別解除安裝,同時GC會對該值進行調整:如果釋放了大量的空間,就適當降低該值;如果釋放了很少的空間,那麼在不超過MaxMetaspaceSize時,適當提高該值。
- -XX:MaxMetaspaceSize,最大空間,預設是沒有限制的,最大記憶體受本地記憶體的限制
參考:深入理解java虛擬機器器第二版