Java內(nèi)存模型(運(yùn)行時(shí)數(shù)據(jù)區(qū)域)

聲明:本文摘抄自《深入理解Java虛擬機(jī)》一書,本文完全為自我學(xué)習(xí),請(qǐng)感興趣的同學(xué)購(gòu)買正版,支持原創(chuàng)

??Java虛擬機(jī)在執(zhí)行Java程序的過程中,會(huì)把它所管理的內(nèi)存劃分為若干個(gè)不同的數(shù)據(jù)區(qū)域。這些區(qū)域都有各自的用途,以及創(chuàng)建和銷毀的時(shí)間,有的區(qū)域隨著虛擬機(jī)的啟動(dòng)而存在,有的區(qū)域則依賴用戶線程的啟動(dòng)和結(jié)束而建立和銷毀。
??根據(jù)《Java虛擬機(jī)規(guī)范(Java SE7 版)》的規(guī)定,Java 虛擬機(jī)包含以下幾個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)域。


Paste_Image.png
1. 程序計(jì)數(shù)器

??程序計(jì)數(shù)器(Program Counter Register)是一塊較小的內(nèi)存空間,可以將它看做當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器。字節(jié)碼解釋器就是通過改變這個(gè)計(jì)數(shù)器的值,來選取下一條需要執(zhí)行的字節(jié)碼指令。
??由于Java虛擬機(jī)的多線程是通過線程輪流切換并分配處理器執(zhí)行時(shí)間的方式來實(shí)現(xiàn)的,在任何一個(gè)確定的時(shí)刻,一個(gè)處理器都只會(huì)處理一條線程中的指令。因此,為了線程切換后能恢復(fù)到正確的執(zhí)行位置,每條線程都需要一個(gè)獨(dú)立的程序計(jì)數(shù)器。
??如果線程正在執(zhí)行的是一個(gè)Java方法,這個(gè)計(jì)數(shù)器記錄的是正在執(zhí)行的字節(jié)碼指令地址。如果線程正在執(zhí)行的是Native方法,這個(gè)計(jì)數(shù)器值為空(Undefined)。此內(nèi)存區(qū)域是唯一一個(gè)在Java虛擬機(jī)規(guī)范中沒有規(guī)定任何OutOfMemoryError情況的區(qū)域。

2. 虛擬機(jī)棧

??與程序計(jì)數(shù)器一樣,Java 虛擬機(jī)棧(Java Virtual Machine Stacks)也是線程私有的,它的生命周期與線程相同。
??虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型,每個(gè)方法在執(zhí)行的同時(shí)都會(huì)創(chuàng)建一個(gè)棧幀(Stack Frame)用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息。
??局部變量表存放了編譯期可知的各種基本數(shù)據(jù)類型(boolean、byte、char、short、int、long、float、double)和對(duì)象引用類型。
??在Java虛擬機(jī)規(guī)范中,對(duì)這個(gè)區(qū)域定義了兩種異常類型:StackOverflowError和OutOfMemoryError。棧內(nèi)存容量可以由-Xss參數(shù)設(shè)定。

3. 本地方法棧

??本地方法棧(Native Method Stack)與虛擬機(jī)棧發(fā)揮的作用相似,只不過Java虛擬機(jī)棧是為虛擬機(jī)執(zhí)行Java方法服務(wù),而本地方法棧是為虛擬機(jī)使用到的Native方法服務(wù)。
??在Java虛擬機(jī)規(guī)范中,對(duì)這個(gè)區(qū)域定義了兩種異常類型:StackOverflowError和OutOfMemoryError。

3. 堆

??Java堆(Heap)是被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。此內(nèi)存區(qū)域用于存放類實(shí)例(對(duì)象)和數(shù)組。
(The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads. The heap is the run-time data area from which memory for all class instances and arrays is allocated.---Java虛擬機(jī)規(guī)范(Java SE7版))
??Java堆可以處于物理上不連續(xù)的內(nèi)存空間,只要邏輯上是連續(xù)的即可。
??在Java虛擬機(jī)規(guī)范中,對(duì)這個(gè)區(qū)域定義了OutOfMemoryError異常類型。通過-Xms參數(shù)設(shè)置堆內(nèi)存的最小值,-Xmx參數(shù)設(shè)置堆內(nèi)存的最大值。通過參數(shù)-XX:+HeapDumpOnOutOfMemoryError可以讓虛擬機(jī)在出現(xiàn)內(nèi)存溢出時(shí)Dump出當(dāng)前的內(nèi)存堆轉(zhuǎn)儲(chǔ)快照以便進(jìn)行事后進(jìn)行分析。

4. 方法區(qū)

??方法區(qū)(Method Area)與Java堆一樣,是各個(gè)線程共享的內(nèi)存區(qū)域,它用于存儲(chǔ)已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯后的代碼等數(shù)據(jù)。Java虛擬機(jī)規(guī)范把方法區(qū)描述為堆的一個(gè)邏輯部分,為了與Java堆區(qū)分開來,給它起了一個(gè)別名叫做Non-Heap(非堆)
??在Java虛擬機(jī)規(guī)范中,對(duì)這個(gè)區(qū)域定義了OutOfMemoryError異常類型。通過-XX:PermSize-XX:MaxPermSize限制方法區(qū)的大小,從而間接限制其中運(yùn)行時(shí)常量池的容量。

5. 運(yùn)行時(shí)常量池

??運(yùn)行時(shí)常量池(Runtime Constant Pool)是方法區(qū)的一部分。Class文件中除了有類的版本信息、字段、方法、接口等描述信息外,還有一項(xiàng)是常量池(Constant Pool Table),用于存放編譯期生成的各種字面量和符號(hào)引用,這部分內(nèi)容將在類加載后進(jìn)入方法區(qū)的運(yùn)行時(shí)常量池中存放。
??運(yùn)行時(shí)常量池相對(duì)與Class文件常量池的另外一個(gè)重要特征是具備動(dòng)態(tài)性,Java語(yǔ)言并不要求常量一定在編譯期才能產(chǎn)生,也就是并非預(yù)置入Class文件中常量池的內(nèi)容才能進(jìn)入方法區(qū)運(yùn)行時(shí)常量池,運(yùn)行期間頁(yè)可能將新的常量放入池中,這種特性被開發(fā)人員利用的比較多的是String類的intern方法。
??在Java虛擬機(jī)規(guī)范中,對(duì)這個(gè)區(qū)域定義了OutOfMemoryError異常類型。

6. 直接內(nèi)存

??直接內(nèi)存(Direct Memory)并不是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分,也不是Java虛擬機(jī)規(guī)范中定義的內(nèi)存區(qū)域。
??在JDK1.4中新加入的NIO(New Input/Output)類,引入了一種基于通道(Channel)與緩沖區(qū)(Buffer)的I/O方式,它可以使用Native函數(shù)庫(kù)直接分配堆外內(nèi)存,然后通過一個(gè)存儲(chǔ)在Java堆中的DirectByteBuffer對(duì)象作為這塊內(nèi)存的引用進(jìn)行操作。這樣能在一些場(chǎng)景中顯著提高性能,因?yàn)楸苊饬嗽贘ava堆和Native堆中來回復(fù)制數(shù)據(jù)。
??直接內(nèi)存不受Java堆大小的限制,但是,既然是內(nèi)存,肯定還是會(huì)受到本機(jī)總內(nèi)存大小及處理器尋址空間的限制。Java各個(gè)內(nèi)存區(qū)域總和+直接內(nèi)存大于物理內(nèi)存限制時(shí),也會(huì)導(dǎo)致內(nèi)存動(dòng)態(tài)擴(kuò)展時(shí)OutOfMemoryError異常。


Reference

Java虛擬機(jī)規(guī)范(Java SE7版)
Java虛擬機(jī)規(guī)范(Java SE8版)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容