JVM(二)----Java運(yùn)行時數(shù)據(jù)區(qū)域

JVM(一)---- 總結(jié)與專題目錄
JVM(二)----Java運(yùn)行時數(shù)據(jù)區(qū)域
JVM(三)----垃圾收集算法及Safe Point介紹
JVM(四)----HotSpot的垃圾收集器與內(nèi)存分配回收策略
JVM(五)----虛擬機(jī)類加載機(jī)制

本文結(jié)構(gòu)如下:
1.運(yùn)行時數(shù)據(jù)區(qū)域總覽
2.每一部分介紹
3.Hotspot永久代在1.8中移除的總結(jié)

首先理解一個概念,就是虛擬機(jī)實(shí)例跟束。當(dāng)啟動一個Java程序時,一個虛擬機(jī)實(shí)例也就誕生了甚疟。當(dāng)該程序關(guān)閉退出揽祥,這個虛擬機(jī)實(shí)例也就隨之消亡俐末。如果同一臺計(jì)算機(jī)上同時運(yùn)行三個Java程序,將得到三個Java虛擬機(jī)實(shí)例。每個Java程序都運(yùn)行于它自己的Java虛擬機(jī)實(shí)例中馁筐。

一盟迟、總覽

Java虛擬機(jī)所管理的內(nèi)存將會包括一下幾個運(yùn)行時數(shù)據(jù)區(qū)域:


Java虛擬機(jī)運(yùn)行時數(shù)據(jù)區(qū).png

注意:線程私有和共享的區(qū)域辖众。

二、介紹每個部分

2.1程序計(jì)數(shù)器

  • 作用:
    記錄當(dāng)前線程所執(zhí)行到的字節(jié)碼的行號。字節(jié)碼解釋器工作的時候就是通過改變這個計(jì)數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令。
  • 意義:
    JVM的多線程是通過線程輪流切換并分配處理器來實(shí)現(xiàn)的,對于我們來說的并行事實(shí)上一個處理器也只會執(zhí)行一條線程中的指令瓢捉。所以迂卢,為了保證各線程指令的安全順利執(zhí)行,每條線程都有獨(dú)立的私有的程序計(jì)數(shù)器腾降。
  • 存儲內(nèi)容
    當(dāng)線程中執(zhí)行的是一個Java方法時奸晴,程序計(jì)數(shù)器中記錄的是正在執(zhí)行的線程的虛擬機(jī)字節(jié)碼指令的地址辕录。
    當(dāng)線程中執(zhí)行的是一個本地方法時蚣旱,程序計(jì)數(shù)器中的值為空异吻。
  • 可能出現(xiàn)異常
    此內(nèi)存區(qū)域是唯一一個在JVM上不會發(fā)生內(nèi)存溢出異常(OutOfMemoryError)的區(qū)域雷猪。

2.2Java虛擬機(jī)棧

  • 作用
    描述Java方法執(zhí)行的內(nèi)存模型验夯,也是線程私有的,生命周期與線程相同。每個方法在執(zhí)行的同時都會開辟一段內(nèi)存區(qū)域用于存放方法運(yùn)行時所需的數(shù)據(jù)泼掠,稱為棧幀,一個棧幀包含如:局部變量表吝梅、操作數(shù)棧苏携、動態(tài)鏈接装蓬、方法出口等信息矛物。
  • 意義
    每個方法從調(diào)用到執(zhí)行結(jié)束忆首,就對應(yīng)著一個棧幀在虛擬機(jī)棧中入棧和出棧的整個過程浸锨。
  • 存儲內(nèi)容
    局部變量表(編譯期可知的各種基本數(shù)據(jù)類型控乾、引用類型和指向一條字節(jié)碼指令的returnAddress類型)、操作數(shù)棧躲雅、動態(tài)鏈接鼎姊、方法出口等信息。
    值得注意的是:局部變量表所需的內(nèi)存空間在編譯期間完成分配。在方法運(yùn)行的階段是不會改變局部變量表的大小的相寇。
  • 可能出現(xiàn)的異常
    如果線程請求的棧深度大于虛擬機(jī)所允許的深度慰于,將拋出StackOverflowError異常。
    如果在動態(tài)擴(kuò)展內(nèi)存的時候無法申請到足夠的內(nèi)存唤衫,就會拋出OutOfMemoryError異常婆赠。

2.3本地方法棧

  • 作用
    為JVM所調(diào)用到的Native方法(即本地方法)服務(wù)。
  • 可能出現(xiàn)的異常
    和虛擬機(jī)棧出現(xiàn)的異常很相像佳励。也是StackOverflowError異常和OutOfMemoryError異常休里。

2.4 Java堆(Heap)

  • 作用
    所有線程共享一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動時創(chuàng)建妙黍,此內(nèi)存區(qū)域的唯一目的就是存放對象實(shí)例。
  • 意義
    1瞧剖、存儲對象實(shí)例拭嫁,更好地分配內(nèi)存。
    2抓于、垃圾回收(Garbage Collection)做粤。堆是垃圾收集器管理的主要區(qū)域。更好地回收內(nèi)存捉撮。
  • 存儲內(nèi)容
    存放對象實(shí)例驮宴,幾乎所有的對象實(shí)例都在這里進(jìn)行分配。堆可以處于物理上不連續(xù)的內(nèi)存空間呕缭,只要邏輯上是連續(xù)的就可以。
    值得注意的是:在JIT編譯器等技術(shù)的發(fā)展下修己,所有對象都在堆上進(jìn)行分配已變得不那么絕對恢总。
  • 可能出現(xiàn)的異常
    實(shí)現(xiàn)堆可以是固定大小的,也可以通過設(shè)置配置文件設(shè)置該為可擴(kuò)展的睬愤。
    如果堆上沒有內(nèi)存進(jìn)行分配片仿,并無法進(jìn)行擴(kuò)展時,將會拋出OutOfMemoryError異常尤辱。

2.5方法區(qū)

  • 作用
    用于存儲運(yùn)行時常量池砂豌、已被虛擬機(jī)加載的類信息、常量光督、靜態(tài)變量阳距、即時編譯器編譯后的代碼等數(shù)據(jù)。
  • 意義
    對運(yùn)行時常量池结借、常量筐摘、靜態(tài)變量等數(shù)據(jù)做出了規(guī)定。
  • 存儲內(nèi)容
    運(yùn)行時常量池(具有動態(tài)性)、已被虛擬機(jī)加載的類信息咖熟、常量圃酵、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù)馍管。
  • 可能出現(xiàn)的異常
    當(dāng)方法區(qū)無法滿足內(nèi)存分配需求時郭赐,將拋出OutOfMemoryError異常。

三确沸、關(guān)于永久代在1.8中移除的總結(jié)

絕大部分 Java 程序員應(yīng)該都見過 "java.lang.OutOfMemoryError: PermGen space "這個異常捌锭。這里的 “PermGen space”其實(shí)指的就是方法區(qū)。不過方法區(qū)和“PermGen space”又有著本質(zhì)的區(qū)別张惹。前者是 JVM 的規(guī)范舀锨,而后者則是 JVM 規(guī)范的一種實(shí)現(xiàn),可以這么理解:方法區(qū)和永久帶的關(guān)系就像Java中接口和實(shí)現(xiàn)接口的類之間的關(guān)系一樣宛逗。并且只有 HotSpot 才有 “PermGen space”坎匿,而對于其他類型的虛擬機(jī),如 JRockit(Oracle)雷激、J9(IBM) 并沒有“PermGen space”替蔬。由于方法區(qū)主要存儲類的相關(guān)信息,所以對于動態(tài)生成類的情況比較容易出現(xiàn)永久代的內(nèi)存溢出屎暇。

在 JDK 1.8 中承桥, HotSpot 已經(jīng)沒有 “PermGen space”這個區(qū)間了,取而代之是一個叫做 Metaspace(元空間) 的東西根悼。下面我們就來看看 Metaspace 與 PermGen space 的區(qū)別凶异。

其實(shí),移除永久代的工作從JDK1.7就開始了挤巡。JDK1.7中剩彬,存儲在永久代的部分?jǐn)?shù)據(jù)就已經(jīng)轉(zhuǎn)移到了Java Heap或者是 Native Heap。但永久代仍存在于JDK1.7中矿卑,并沒完全移除喉恋,譬如符號引用(Symbols)轉(zhuǎn)移到了native heap;字面量(interned strings)轉(zhuǎn)移到了java heap母廷;類的靜態(tài)變量(class statics)轉(zhuǎn)移到了java heap轻黑。我們可以通過一段程序來比較 JDK 1.6 與 JDK 1.7及 JDK 1.8 的區(qū)別,以字符串常量為例:

package com.paddx.test.memory;
 
import java.util.ArrayList;
import java.util.List;
 
public class StringOomMock {
    static String  base = "string";
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        for (int i=0;i< Integer.MAX_VALUE;i++){
            String str = base + base;
            base = str;
            list.add(str.intern());
        }
    }
}

這段程序不斷的生成新的字符串琴昆,并且通過intern方法將字符串放到字符串常量池中氓鄙,這樣可以比較快速的消耗內(nèi)存。我們通過 JDK 1.6业舍、JDK 1.7 和 JDK 1.8 分別運(yùn)行:

JDK 1.6 的運(yùn)行結(jié)果:


image.png

JDK 1.7的運(yùn)行結(jié)果:


image.png

JDK 1.8的運(yùn)行結(jié)果:


image.png

從上述結(jié)果可以看出玖详,JDK 1.6下把介,會出現(xiàn)“PermGen Space”的內(nèi)存溢出,而在 JDK 1.7和 JDK 1.8 中蟋座,會出現(xiàn)堆內(nèi)存溢出拗踢,并且 JDK 1.8中 PermSize 和 MaxPermGen 已經(jīng)無效。因此向臀,可以大致驗(yàn)證 JDK 1.7 和 1.8 將字符串常量由永久代轉(zhuǎn)移到堆中巢墅,并且 JDK 1.8 中已經(jīng)不存在永久代的結(jié)論。

元空間的本質(zhì)和永久代類似券膀,都是對JVM規(guī)范中方法區(qū)的實(shí)現(xiàn)君纫。不過元空間與永久代之間最大的區(qū)別在于:元空間并不在虛擬機(jī)中,而是使用本地內(nèi)存芹彬。因此蓄髓,默認(rèn)情況下,元空間的大小僅受本地內(nèi)存限制舒帮,但可以通過以下參數(shù)來指定元空間的大谢岷取:

-XX:MetaspaceSize,初始空間大小玩郊,達(dá)到該值就會觸發(fā)垃圾收集進(jìn)行類型卸載肢执,同時GC會對該值進(jìn)行調(diào)整:如果釋放了大量的空間,就適當(dāng)降低該值译红;如果釋放了很少的空間,那么在不超過MaxMetaspaceSize時侦厚,適當(dāng)提高該值耻陕。
-XX:MaxMetaspaceSize刨沦,最大空間,默認(rèn)是沒有限制的已卷。

除了上面兩個指定大小的選項(xiàng)以外淳蔼,還有兩個與 GC 相關(guān)的屬性:

-XX:MinMetaspaceFreeRatio,在GC之后鹉梨,最小的Metaspace剩余空間容量的百分比讳癌,減少為分配空間所導(dǎo)致的垃圾收集

-XX:MaxMetaspaceFreeRatio存皂,在GC之后晌坤,最大的Metaspace剩余空間容量的百分比逢艘,減少為釋放空間所導(dǎo)致的垃圾收集。

最后總結(jié)一下為什么移除永久帶而使用元空間的原因吧:

  • 字符串存在永久代中骤菠,容易出現(xiàn)性能問題和內(nèi)存溢出它改。
  • 類及方法的信息等比較難確定其大小,因此對于永久代的大小指定比較困難商乎,太小容易出現(xiàn)永久代溢出央拖,太大則容易導(dǎo)致老年代溢出。
  • 永久代會為 GC 帶來不必要的復(fù)雜度鹉戚,并且回收效率偏低鲜戒。
  • Oracle 可能會將HotSpot 與 JRockit 合二為一。

參考資料:http://www.cnblogs.com/paddix/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末抹凳,一起剝皮案震驚了整個濱河市遏餐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赢底,老刑警劉巖失都,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異颖系,居然都是意外死亡嗅剖,警方通過查閱死者的電腦和手機(jī)揖赴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進(jìn)店門代赁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沦辙,“玉大人擦俐,你說我怎么就攤上這事糯而∈χ#” “怎么了添忘?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵察皇,是天一觀的道長不傅。 經(jīng)常有香客問我旅掂,道長,這世上最難降的妖魔是什么访娶? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任商虐,我火速辦了婚禮,結(jié)果婚禮上崖疤,老公的妹妹穿的比我還像新娘秘车。我一直安慰自己,他們只是感情好劫哼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布叮趴。 她就那樣靜靜地躺著,像睡著了一般权烧。 火紅的嫁衣襯著肌膚如雪眯亦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天妻率,我揣著相機(jī)與錄音,去河邊找鬼糯耍。 笑死囊嘉,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的舵鳞。 我是一名探鬼主播琢蛤,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼博其,長吁一口氣:“原來是場噩夢啊……” “哼慕淡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起傻寂,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤疾掰,失蹤者是張志新(化名)和其女友劉穎徐紧,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拂檩,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年呀潭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片糠聪。...
    茶點(diǎn)故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡谐鼎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出身害,到底是詐尸還是另有隱情,我是刑警寧澤塌鸯,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布唐片,位于F島的核電站费韭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏星持。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一羹令、第九天 我趴在偏房一處隱蔽的房頂上張望损痰。 院中可真熱鬧,春花似錦肪凛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拱烁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間戏自,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工志衣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留猛们,地道東北人。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓和二,卻偏偏與公主長得像,于是被迫代替她去往敵國和親惯吕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評論 2 354