Java內(nèi)存模型整理

歡迎訪問我的博客:http://wangnan.tech

參考:
http://gityuan.com/2016/01/09/java-memory/

  • 一般地大家講到的Java內(nèi)存其實就是Jvm內(nèi)存
  • Java代碼是運行在Java虛擬機之上的,由Java虛擬機通過解釋執(zhí)行(解釋器)或編譯執(zhí)行(即時編譯器)來完成,故Java內(nèi)存模型,也就是指Java虛擬機的運行時內(nèi)存模型。

內(nèi)存模型圖

詳細(xì)介紹

程序計數(shù)器PC

  • 程序計數(shù)器PC,當(dāng)前線程所執(zhí)行的字節(jié)碼行號指示器。每個線程都有自己計數(shù)器,是私有內(nèi)存空間,該區(qū)域是整個內(nèi)存中較小的一塊。

  • 當(dāng)線程正在執(zhí)行一個Java方法時,PC計數(shù)器記錄的是正在執(zhí)行的虛擬機字節(jié)碼的地址;當(dāng)線程正在執(zhí)行的一個Native方法時,PC計數(shù)器則為空(Undefined)。

虛擬機棧

虛擬機棧,生命周期與線程相同,是Java方法執(zhí)行的內(nèi)存模型。每個方法(不包含native方法)執(zhí)行的同時都會創(chuàng)建一個棧幀結(jié)構(gòu),方法執(zhí)行過程,對應(yīng)著虛擬機棧的入棧到出棧的過程。

棧幀(Stack Frame)結(jié)構(gòu)
棧幀是用于支持虛擬機進(jìn)行方法執(zhí)行的數(shù)據(jù)結(jié)構(gòu),是屬性運行時數(shù)據(jù)區(qū)的虛擬機站的棧元素。見上圖, 棧幀包括:

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

異常(Exception)
Java虛擬機規(guī)范規(guī)定該區(qū)域有兩種異常:

  • StackOverFlowError:當(dāng)線程請求棧深度超出虛擬機棧所允許的深度時拋出
  • OutOfMemoryError:當(dāng)Java虛擬機動態(tài)擴展到無法申請足夠內(nèi)存時拋出

本地方法棧

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

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

方法區(qū)

方法區(qū)主要存放的是已被虛擬機加載的類信息、常量、靜態(tài)變量、編譯器編譯后的代碼等數(shù)據(jù)。GC在該區(qū)域出現(xiàn)的比較少。

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

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

  • 字面量:與Java語言層面的常量概念相近,包含文本字符串、聲明為final的常量值等。

  • 符號引用:編譯語言層面的概念,包括以下3類:

  1. 類和接口的全限定名
  2. 字段的名稱和描述符
  3. 方法的名稱和描述符

該區(qū)域會拋出OutOfMemoryError異常。

Java堆

Java堆,是Java虛擬機管理的最大的一塊內(nèi)存,也是GC的主戰(zhàn)場,里面存放的是幾乎所有的對象實例和數(shù)組數(shù)據(jù)。JIT編譯器有棧上分配、標(biāo)量替換等優(yōu)化技術(shù)的實現(xiàn)導(dǎo)致部分對象實例數(shù)據(jù)不存在Java堆,而是棧內(nèi)存。

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

對象創(chuàng)建的過程是在堆上分配著實例對象,那么對象實例的具體結(jié)構(gòu)如下:

對于填充數(shù)據(jù)不是一定存在的,僅僅是為了字節(jié)對齊。HotSpot VM的自動內(nèi)存管理要求對象起始地址必須是8字節(jié)的整數(shù)倍。對象頭本身是8的倍數(shù),當(dāng)對象的實例數(shù)據(jù)不是8的倍數(shù),便需要填充數(shù)據(jù)來保證8字節(jié)的對齊。該功能類似于高速緩存行的對齊。

另外,關(guān)于在堆上內(nèi)存分配是并發(fā)進(jìn)行的,虛擬機采用CAS加失敗重試保證原子操作,或者是采用每個線程預(yù)先分配TLAB內(nèi)存.

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容