Java虛擬機器-執行時資料區
簡圖
執行緒私有區域:虛擬機器棧、本地方法棧和程式計數器
執行緒共享區域:堆和方法區(元空間區)
執行緒私有區域
程式計數器
作用:讀取程式計數器的值來選取下一條位元組碼指令,並完成分支、迴圈、跳轉、異常處理、執行緒回覆等
-
程式計數器是一個很小的內容空間,可以看做是當前執行緒所執行的位元組碼的行號指示器。在Java虛擬機器的概念模型中,位元組碼直譯器工作是通過改變這個計時器的值來選取下一條需要執行的位元組碼指令,他是程式控制流的指示器,分支、迴圈、跳轉、異常處理、執行緒回覆等基礎功能都需要依賴這個計數器來完成
-
每個執行緒都有一個獨立的執行緒計數器,各條執行緒之間計時器互不影響,獨立儲存。生命週期與執行緒的生命週期保持一致
-
如果執行緒正在執行的是一個Java方法,程式計數器記錄的是正在執行的虛擬機器位元組碼指令的地址;如果正在執行的是本地方法(呼叫C類庫執行)程式計數器為空(undefined)
-
它是唯一一個在《Java虛擬機器規範》中沒有規定任何OutOfMemoryError情況的區域
編譯如下程式碼後使用javap
反編譯工具檢視位元組碼檔案Test.class
public class Test {
public static void main(String[] args) {
int a = 1;
int b = 2;
System.out.println(a + b);
}
}
// 指令:javap -v Test.class
在反編譯結果中找到main()
方法
途圖中紅框內的數字為指令地址,執行引擎通過讀取指令地址完成方法的執行
虛擬機器棧
作用:在Java程式執行期間,它儲存方法的區域性變數、部分結果,並參與方法的呼叫和返回
- 每個方法執行的時候,Java虛擬機器都會同步建立一個棧幀(Stack Frame)用於儲存區域性變數表、運算元棧、動態連結、方法出口等資訊,對應著一個棧幀在虛擬機器棧中從入棧到出棧的過程
- 屬執行緒私有區域
- 生命週期與執行緒生命週期相同
- 此區域規定了兩類異常狀況:如果執行緒請求的棧深度大於虛擬機器的所允許的深度,將丟擲
StackOverFlowError
異常;如果Java虛擬機器棧容量可以動態擴充套件,當棧擴充套件時無法申請到足夠的記憶體會丟擲OutOfMemoryError
異常 - 使用
-Xss
設定棧的大小;棧的大小直接決定了函式呼叫的最大可達深度 - 棧的深度通常只有幾百K,但是它決定了函式呼叫深度;如果程式使用了很深的遞迴函式,而棧空間非常小,此時很有可能發生棧溢位(java.lang.StackOverflowError)
- 對於多執行緒任務,應縮小棧,反之
虛擬機器棧的特點:
-
是一種快速有效的分配儲存方式,訪問速度僅次於程式計數器
-
JVM直接對Java棧的操作只有兩個:
- 方法的執行對應入棧
- 方法結束執行對應出棧
-
虛擬機器棧不存在垃圾回收問題
調整棧的大小
通過在Idea中設定-Xss
引數,觀察程式碼的執行情況
- 設定棧大小為128k,當棧深度為967時丟擲棧溢位異常
- 設定棧大小為256k,當棧深度為2250時丟擲棧溢位異常
棧幀的內部結構
-
區域性變數表
- 定義為一個數字陣列,主要用於儲存方法引數和定義在方法體內的區域性變數,這些資料型別包括八種基本資料型別、物件引用,以及returnAddress型別
- 區域性變數表建立線上程的棧上,是執行緒私有資料,因此不存在資料安全問題
- 區域性變數表所需的容量大小是編譯期確定下來的,在執行期間不會改變區域性變數表的大小
-
運算元棧
在方法執行過程中,根據位元組碼指令,往棧中寫入資料或提取資料,即入棧和出棧。使用javap指令可檢視運算元棧的深度
- 動態連結
每一個棧幀內部都包含一個指向執行時常量池中該幀所屬方法的引用。包含這個引用的目的就是為了當前方法的程式碼能夠實現動態連結。動態連結的作用是將符號引用轉換為呼叫方法的直接引用。
-
方法返回地址
存放呼叫該方法的的PC暫存器的值 ;程式正常退出時返回該值,異常退出時不返回該值
-
一些附加資訊
本地方法棧
本地方法棧用於管理本地方法的呼叫(c或c++),會丟擲
StackOverFlowError
和OutOfMemoryError
執行緒共享區域
堆
- 一個Java程式對應一個JVM例項,一個JVM例項存在一個執行時資料區,多個執行緒共享堆和方法區
- JVM啟動時堆被建立且空間大小以確定,是JVM 管理的最大的一個記憶體區域
- 堆的大小是可調節的
- 堆可以處於物理不連續,但在邏輯上應該是視為連續的
- 所有的執行緒共享堆,還可以劃分出執行緒私有緩衝區(TLAB)
- 大多數物件例項和陣列都分配在堆上
- 陣列和物件可能永遠不會儲存在棧上,棧幀中儲存引用,引用指向堆中的位置
- 方法執行結束後,堆中的物件不會立即移除,在垃圾收集的時候才會被移除
- 此區域是GC的主要工作區域
細分堆記憶體
- Java7及之前
- 年輕代
- 老年代
- 永久代
- Java8及之後
- 年輕代
- Eden Space、Survivor0、Survivor1
- 老年代 :Old Gen
- 元空間:Metaspace
- 年輕代
設定堆空間的的大小
-Xms
:memory start; 用來設定堆(年輕代+老年代)的初始記憶體大小
-Xmx
:memory max;用來設定堆(年輕代+老年代)的最大記憶體大小
-XX:+PrintGCDetails 輸出GC資訊
年輕代和老年代
- 使用
-XX:NewRatio
調整年輕代和老年代的比例,例如:-XX:NewRatio=3,表示年輕代佔1份,老年代佔3份;對應四分之一和四分之三 - 預設情況下
-XX:NewRatio=2
- 年輕代中的分配比例為8:1:1,使用
-XX:-UseAdaptiveSizePolicy
關閉自適應記憶體分配策略 - 使用
-Xn
設定年輕代的空間
方法區
參考資料
- 【Java虛擬機器探究】5.常用JVM配置引數-棧的分配引數
- 深入理解Java虛擬機器-周志明(第二版)
相關文章
- Java虛擬機器 —— 執行時資料區Java虛擬機
- java虛擬機器——執行時資料區域Java虛擬機
- Java 虛擬機器執行時資料區詳解Java虛擬機
- Java 虛擬機器中的執行時資料區分析Java虛擬機
- Java虛擬機器執行時資料區域劃分Java虛擬機
- Golang實現JAVA虛擬機器-執行時資料區GolangJava虛擬機
- JVM虛擬機器-執行時資料區概述JVM虛擬機
- 虛擬機器系列 | JVM執行時資料區虛擬機JVM
- 詳解Java 虛擬機器(第①篇)——執行時資料區域Java虛擬機
- Java虛擬機器--方法區(執行時常量池)Java虛擬機
- 關於Java虛擬機器執行時資料區域的總結Java虛擬機
- Java虛擬機器(一)結構原理與執行時資料區域Java虛擬機
- 深入理解Java虛擬機器筆記之一Java執行時資料區Java虛擬機筆記
- JDK1.8-Java虛擬機器執行時資料區域和HotSpot虛擬機器的記憶體模型JDKJava虛擬機HotSpot記憶體模型
- 【JVM從小白學成大佬】2.Java虛擬機器執行時資料區JVMJava虛擬機
- jvm-執行時資料區(程式計數器、Java虛擬機器棧、本地方法棧)JVMJava虛擬機
- Java 虛擬機器:看完就懂 JVM 架構和執行時資料區 (記憶體區域)Java虛擬機JVM架構記憶體
- java虛擬機器的執行原理Java虛擬機
- java虛擬機器執行時記憶體分割槽Java虛擬機記憶體
- 你還在看《深入理解Java虛擬機器》的執行時資料模型嗎?Java虛擬機模型
- 深入學習Java虛擬機器——虛擬機器位元組碼執行引擎Java虛擬機
- 深入理解Java虛擬機器8 虛擬機器位元組碼執行引擎Java虛擬機
- [深入理解Java虛擬機器]執行緒Java虛擬機執行緒
- Java虛擬機器執行機制與相關概念Java虛擬機
- Java虛擬機器詳解(二)------執行時記憶體結構Java虛擬機記憶體
- Java 虛擬機器之二:Java語言的執行機制Java虛擬機
- 弄清Java虛擬機器GC的執行過程Java虛擬機GC
- [Java虛擬機器]Java記憶體模型與執行緒Java虛擬機記憶體模型執行緒
- Dalvik虛擬機器、Java虛擬機器與ART虛擬機器虛擬機Java
- Java虛擬機器:記憶體管理與執行引擎Java虛擬機記憶體
- Java虛擬機器08——Java記憶體模型與執行緒Java虛擬機記憶體模型執行緒
- java的執行時資料區域Java
- Java-JVM-執行時資料區JavaJVM
- 深入理解虛擬機器之虛擬機器位元組碼執行引擎虛擬機
- java虛擬機器和Dalvik虛擬機器Java虛擬機
- Android 虛擬機器 Vs Java 虛擬機器Android虛擬機Java
- Java虛擬機器11:執行期優化Java虛擬機優化
- Java虛擬機器09——執行緒安全與鎖優化Java虛擬機執行緒優化