程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Jvm內存模型概述

Jvm內存模型概述

編輯:關於JAVA
 

java是在java虛擬機上運行,一般地大家講到的Java內存其實就是Jvm內存

一、內存模型

Java內存模型,往往是指Java程序在運行時內存的模型,而Java代碼是運行在Java虛擬機之上的,由Java虛擬機通過解釋執行(解釋器)或編譯執行(即時編譯器)來完成,故Java內存模型,也就是指Java虛擬機的運行時內存模型。

作為Java開發人員來說,並不需要像C/C++開發人員,需要時刻注意內存的釋放,而是全權交給虛擬機去管理,那麼有就必要了解虛擬機的運行時內存是如何構成的。運行時內存模型,分為線程私有和共享數據區兩大類,其中線程私有的數據區包含程序計數器、虛擬機棧、本地方法區,所有線程共享的數據區包含Java堆、方法區,在方法區內有一個常量池。

jvm_memory_1

(1)線程私有區:

  • 程序計數器,記錄正在執行的虛擬機字節碼的地址;
  • 虛擬機棧:方法執行的內存區,每個方法執行時會在虛擬機棧中創建棧幀;
  • 本地方法棧:虛擬機的Native方法執行的內存區;

(2)線程共享區:

  • Java堆:對象分配內存的區域;
  • 方法區:存放類信息、常量、靜態變量、編譯器編譯後的代碼等數據;
    • 常量池:存放編譯器生成的各種字面量和符號引用,是方法區的一部分。

對於大多數的程序員來說,Java內存比較流行的說法便是堆和棧,這其實是非常粗略的一種劃分,這種劃分的”堆”對應內存模型的Java堆,”棧”是指虛擬機棧,然而Java內存模型遠比這更復雜,想深入了解Java的內存,還是有必要明白整個內存模型。

二、 詳細模型

運行時內存分為五大塊區域(常量池屬於方法區,算作一塊區域),前面簡要介紹了每個區域的功能,那接下來再詳細說明每個區域的內容,Java內存總體結構圖如下:

stack_heap_info

2.1 程序計數器PC

程序計數器PC,當前線程所執行的字節碼行號指示器。每個線程都有自己計數器,是私有內存空間,該區域是整個內存中較小的一塊。

當線程正在執行一個Java方法時,PC計數器記錄的是正在執行的虛擬機字節碼的地址;當線程正在執行的一個Native方法時,PC計數器則為空(Undefined)。

2.2 虛擬機棧

虛擬機棧,生命周期與線程相同,是Java方法執行的內存模型。每個方法(不包含native方法)執行的同時都會創建一個棧幀結構,方法執行過程,對應著虛擬機棧的入棧到出棧的過程。

棧幀(Stack Frame)結構

棧幀是用於支持虛擬機進行方法執行的數據結構,是屬性運行時數據區的虛擬機站的棧元素。見上圖, 棧幀包括:

  1. 局部變量表 (locals大小,編譯期確定),一組變量存儲空間, 容量以slot為最小單位。
  2. 操作棧(stack大小,編譯期確定),操作棧元素的數據類型必須與字節碼指令序列嚴格匹配
  3. 動態連接, 指向運行時常量池中該棧幀所屬方法的引用,為了 動態連接使用。
    • 前面的解析過程其實是靜態解析;
    • 對於運行期轉化為直接引用,稱為動態解析。
  4. 方法返回地址
    • 正常退出,執行引擎遇到方法返回的字節碼,將返回值傳遞給調用者
    • 異常退出,遇到Exception,並且方法未捕捉異常,那麼不會有任何返回值。
  5. 額外附加信息,虛擬機規范沒有明確規定,由具體虛擬機實現。

因此,一個棧幀的大小不會受到

異常(Exception)

Java虛擬機規范規定該區域有兩種異常:

  • StackOverFlowError:當線程請求棧深度超出虛擬機棧所允許的深度時拋出
  • OutOfMemoryError:當Java虛擬機動態擴展到無法申請足夠內存時拋出

2.3 本地方法棧

本地方法棧則為虛擬機使用到的Native方法提供內存空間,而前面講的虛擬機棧式為Java方法提供內存空間。有些虛擬機的實現直接把本地方法棧和虛擬機棧合二為一,比如非常典型的Sun HotSpot虛擬機。

異常(Exception):Java虛擬機規范規定該區域可拋出StackOverFlowError和OutOfMemoryError。

2.4 Java堆

Java堆,是Java虛擬機管理的最大的一塊內存,也是GC的主戰場,裡面存放的是幾乎所有的對象實例和數組數據。JIT編譯器有棧上分配、標量替換等優化技術的實現導致部分對象實例數據不存在Java堆,而是棧內存。

  • 從內存回收角度,Java堆被分為新生代和老年代;這樣劃分的好處是為了更快的回收內存;
  • 從內存分配角度,Java堆可以劃分出線程私有的分配緩沖區(Thread Local Allocation Buffer,TLAB);這樣劃分的好處是為了更快的分配內存;

對象創建的過程是在堆上分配著實例對象,那麼對象實例的具體結構如下:

java_object

對於填充數據不是一定存在的,僅僅是為了字節對齊。HotSpot VM的自動內存管理要求對象起始地址必須是8字節的整數倍。對象頭本身是8的倍數,當對象的實例數據不是8的倍數,便需要填充數據來保證8字節的對齊。該功能類似於高速緩存行的對齊。

另外,關於在堆上內存分配是並發進行的,虛擬機采用CAS加失敗重試保證原子操作,或者是采用每個線程預先分配TLAB內存.

異常(Exception):Java虛擬機規范規定該區域可拋出OutOfMemoryError。

2.5 方法區

方法區主要存放的是已被虛擬機加載的類信息、常量、靜態變量、編譯器編譯後的代碼等數據。GC在該區域出現的比較少。

異常(Exception):Java虛擬機規范規定該區域可拋出OutOfMemoryError。

2.6 運行時常量池

運行時常量池也是方法區的一部分,用於存放編譯器生成的各種字面量和符號引用。運行時常量池除了編譯期產生的Class文件的常量池,還可以在運行期間,將新的常量加入常量池,比較常見的是String類的intern()方法。

  • 字面量:與Java語言層面的常量概念相近,包含文本字符串、聲明為final的常量值等。
  • 符號引用:編譯語言層面的概念,包括以下3類:
    • 類和接口的全限定名
    • 字段的名稱和描述符
    • 方法的名稱和描述符

但是該區域不會拋出OutOfMemoryError異常。

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved