文章目錄
- 參考
- JVM內存區域
- 程序計數器
- 虛擬機棧
- 本地方法棧
- 堆
- 方法區
- 符號引用與直接引用
- 運行時常量池
- 字符串常量池
- 直接內存
參考
JavaGuide
JVM內存區域
程序計數器
程序計數器是一塊較小的內存空間,可以看做是當前線程所執行的字節碼的行號指示器,各線程之間計數器互不影響。
程序計數器是唯一一個不會出現OutOfMemoryError
的內存區域,它的生命周期與線程同步。
虛擬機棧
除了一些Native方法調用通過本地方法棧實現,其他所有的Java方法調用都是通過棧來實現的,每一次方法調用都會入棧,每一個方法返回都會出棧,每個方法對應一個棧幀,棧幀內部結構如下:
- 局部變量表:存放了編譯時可知的各種數據類型和對象引用。
- 操作數棧:主要作為方法調用的中轉站,用于存放方法執行過程中產生的中間計算結果和臨時變量。
- 動態鏈接:當一個方法要調用其他方法時,需要將符號引用轉換為調用方法的直接引用,即動態鏈接。
- 方法返回:一種是隨return語句正常返回,一種是拋出異常,兩種都會導致棧幀被彈出,方法結束。
本地方法棧
類似于虛擬機棧,虛擬機棧為虛擬機執行Java方法(字節碼)服務,本地方法棧為虛擬機使用的Native方法服務,在HotSpot虛擬機中,兩棧合二為一。
Native方法被執行時在本地方法棧也會創建棧幀,結構同上。
堆
堆是Java虛擬機所管理的內存中最大的一塊,是所有線程共享的一塊內存區域,唯一作用是存放對象實例,幾乎所有的對象實例以及數組都在這里分配內存。
但隨著JIT編譯器的發展產生了逃逸分析技術,如果某些方法中的對象引用沒有被返回或者未被外面使用,那么對象可以直接在棧上分配內存。
Java堆是垃圾收集器管理的主要區域,在JDK7及之前,堆從垃圾回收的角度被劃分為新生代、老年代和永久代;在JDK8之后永久代被元空間取代,元空間使用本地內存。
方法區
方法區是一種設計規范,屬于JVM運行時數據區域的一塊邏輯區域,是各個線程共享的內存區域,當虛擬機要使用一個類時,它需要讀取并解析Class文件獲取相關信息,再將信息存入方法區,主要是類信息、字段信息、方法信息、常量、靜態變量等。
永久代和元空間是實現方法區的兩種方式,棄用永久代的主要原因是: 整個永久代有一個JVM本身設定的固定上限,不能調整,而元空間放在本地內存,不容易溢出。
符號引用與直接引用
符號引用以一組符號來描述所引用的目標,可以是任何形式的字面量,比如類和接口的全限定名、字段的名稱和描述符、方法的名稱和描述符等,在編譯期或者運行期間生成,不依賴于具體的內存地址,而是在運行時根據上下文信息去定位目標。
直接引用時一種直接指向目標的內存地址或者偏移量,與內存地址直接相關,如指向對象實例的指針、指向類的變量的指針等。
在程序運行時需要通過符號引用來找到對應的直接引用,這個過程稱為解析,他是Java虛擬機執行引擎的一部分。
使用兩種引用的原因:
- 動態鏈接:符號引用提供了一種在編譯期間和運行期間都能定位目標的方法,使得Java能實現動態鏈接,即在運行時才確定最終目標。
- 運行時多態:符號引用提供了一種描述方法的方式,同上。
- 內存管理:使虛擬機更靈活地進行內存管理,如動態加載和卸載類。
- 平臺無關性:不需要針對不同平臺進行特定的編譯或鏈接。
運行時常量池
常量池表,用于存放編譯期生成的各種字面量和符號引用,類似符號表。
字面量是源代碼中的固定值,包括整數、浮點數和字符串字面量。
符號引用包括類符號引用、字段符號引用、方法符號引用、接口方法符號等。
字符串常量池
字符串常量池是JVM為了提升性能和減少內存消耗針對字符串專門開辟的一塊區域,主要是為了避免重復創建字符串。
JDK1.7將字符串常量池移動到堆中,因為永久代垃圾回收效率太低,只有在整堆收集的時候才會被執行,而大量字符串通常是需要被及時回收的,因此移動到堆中。
直接內存
直接內存是一種特殊的內存緩沖區,通過JNI的方式在本地內存中分配。
CSDN