JVM之詳細(xì)分析java內(nèi)存結(jié)構(gòu)模型

java開發(fā)過程中經(jīng)常見到一堆有關(guān)內(nèi)存的錯(cuò)誤疲牵,比如:

Exception in thread “main”: java.lang.OutOfMemoryError: Java heap space
Exception in thread “main”: java.lang.OutOfMemoryError: PermGen space

我們統(tǒng)一叫做內(nèi)存溢出承二,那么這些異常的底層到底有什么不同,各自屬于JVM運(yùn)行時(shí)的哪塊區(qū)域纲爸?該怎么解決呢亥鸠?想要徹徹底底的弄清楚這些疑惑,了解JVM內(nèi)存結(jié)構(gòu)就會隨之而來识啦。

JVM內(nèi)存概念

首先负蚊,Java源代碼文件(.java后綴)會被Java編譯器編譯為字節(jié)碼文件(.class后綴),然后由JVM中的類加載器加載各個(gè)類的字節(jié)碼文件颓哮,加載完畢之后家妆,交由JVM執(zhí)行引擎執(zhí)行也就是常說的java項(xiàng)目運(yùn)行過程。在整個(gè)程序執(zhí)行過程中冕茅,JVM會用一段空間來存儲程序執(zhí)行期間需要用到的數(shù)據(jù)和相關(guān)信息伤极,這段空間一般被稱作為Runtime Data Area(運(yùn)行時(shí)數(shù)據(jù)區(qū)),也就是我們今天分析的JVM內(nèi)存姨伤。
在知道了JVM內(nèi)存是什么東西之后哨坪,下面我們就開始分析它的組成。

JVM內(nèi)存組成

JVM內(nèi)存由程序計(jì)數(shù)器(Program Counter Register)姜挺、Java棧(JVM Stack)齿税、本地方法棧(Native Method Stack)、方法區(qū)(Method Area)炊豪、堆(Heap)組成凌箕。

281726404166686.jpg

如上圖所示,下面我們逐個(gè)分析词渤。

堆-Heap

Java堆(Java Heap)是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊牵舱。此內(nèi)存區(qū)域的唯一目的就是存放對象實(shí)例,幾乎所有的對象實(shí)例都在這里分配內(nèi)存缺虐。內(nèi)存分配主要是由程序員顯示的使用new關(guān)鍵字來觸發(fā)的芜壁,至于new出來的這部分內(nèi)存在哪分配,如何分配,則是JAVA虛擬機(jī)來決定慧妄。而這部分內(nèi)存的釋放顷牌,則是由自動(dòng)內(nèi)存管理系統(tǒng)(以下簡稱GC)來管理的。Java堆是被所有線程共享的一塊內(nèi)存區(qū)域塞淹,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建窟蓝。
Java堆是垃圾收集器管理的主要區(qū)域,因此很多時(shí)候也被稱做“GC堆”饱普。如果從內(nèi)存回收的角度看运挫,由于現(xiàn)在收集器基本都是采用的分代收集算法,所以Java堆中還可以細(xì)分為:新生代和老年代套耕;再細(xì)致一點(diǎn)的有Eden空間谁帕、From Survivor空間、To Survivor空間等冯袍。根據(jù)Java虛擬機(jī)規(guī)范的規(guī)定匈挖,Java堆可以處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上是連續(xù)的即可颠猴,就像我們的磁盤空間一樣关划。在實(shí)現(xiàn)時(shí),既可以實(shí)現(xiàn)成固定大小的翘瓮,也可以是可擴(kuò)展的贮折,不過當(dāng)前主流的虛擬機(jī)都是按照可擴(kuò)展來實(shí)現(xiàn)的(通過-Xmx和-Xms控制)。如果在堆中沒有內(nèi)存完成實(shí)例分配资盅,并且堆也無法再擴(kuò)展時(shí)调榄,將會拋出OutOfMemoryError異常。

方法區(qū)-Method Area

方法區(qū)(Method Area)與Java堆一樣呵扛,是各個(gè)線程共享的內(nèi)存區(qū)域每庆,它用于存儲已被虛擬機(jī)加載的類信息、常量今穿、靜態(tài)變量缤灵、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。雖然Java虛擬機(jī)規(guī)范把方法區(qū)描述為堆的一個(gè)邏輯部分蓝晒,但是它卻有一個(gè)別名叫做Non-Heap(非堆)腮出,目的應(yīng)該是與Java堆區(qū)分開來。
我們知道堆中存儲的是程序員new出來的對象實(shí)例芝薇,那么方法區(qū)存儲的是什么胚嘲?

1.方法區(qū)包含所有的class和static變量和常量。
2.方法區(qū)中包含類的信息洛二,比如各種方法等馋劈。

舉個(gè)例子:

public class HelloWorld {
    private static Logger LOGGER = Logger.getLogger(HelloWorld.class.getName());
    public void sayHello(String message) {
        SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.YYYY");
        String today = formatter.format(new Date());
        LOGGER.info(today + ": " + message);
    }
}

上述代碼運(yùn)行內(nèi)存分配如下

JUtH_20121024_RuntimeDataAreas_4_MemoryModel.png

對于習(xí)慣在HotSpot虛擬機(jī)上開發(fā)和部署程序的開發(fā)者來說攻锰,很多人愿意把方法區(qū)稱為“永久代”(Permanent Generation),Java虛擬機(jī)規(guī)范對這個(gè)區(qū)域的限制非常寬松妓雾,相對而言娶吞,垃圾收集行為在這個(gè)區(qū)域是比較少出現(xiàn)的,但并非數(shù)據(jù)進(jìn)入了方法區(qū)就如永久代的名字一樣“永久”存在了君珠。這個(gè)區(qū)域的內(nèi)存回收目標(biāo)主要是針對常量池的回收和對類型的卸載寝志,一般來說這個(gè)區(qū)域的回收“成績”比較難以令人滿意,尤其是類型的卸載策添,條件相當(dāng)苛刻,但是這部分區(qū)域的回收確實(shí)是有必要的毫缆。根據(jù)Java虛擬機(jī)規(guī)范的規(guī)定唯竹,當(dāng)方法區(qū)無法滿足內(nèi)存分配需求時(shí),將拋出OutOfMemoryError異常苦丁。

Java棧(JVM Stack)

Java虛擬機(jī)棧(Java Virtual Machine Stacks)是線程私有的浸颓,它的生命周期與線程相同。
虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個(gè)方法被執(zhí)行的時(shí)候都會同時(shí)創(chuàng)建一個(gè)棧幀(Stack Frame)用于存儲局部變量表旺拉、操作棧产上、動(dòng)態(tài)鏈接、方法出口等信息蛾狗。每一個(gè)方法被調(diào)用直至執(zhí)行完成的過程晋涣,就對應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中從入棧到出棧的過程。

  • 棧幀:簡單點(diǎn)說沉桌,可以解釋為是一個(gè)方法運(yùn)行時(shí)谢鹊,臨時(shí)數(shù)據(jù)的存儲區(qū)域,具體點(diǎn)說留凭,它里面包括了數(shù)據(jù)和部分的過程結(jié)果佃扼,與此同時(shí),它又肩負(fù)著處理方法返回值蔼夜、動(dòng)態(tài)鏈接以及異常分派的任務(wù)兼耀。棧幀是隨著方法的創(chuàng)建而創(chuàng)建,隨著方法的結(jié)束而銷毀求冷,如果方法拋出異常瘤运,也算方法結(jié)束。然而在每一個(gè)棧幀中遵倦,都有著自己的局部變量表以及操作數(shù)棧以及對當(dāng)前類的運(yùn)行時(shí)常量池的引用尽超。
  • 局部變量表:它是一個(gè)方法局部變量的列表,是在編譯時(shí)期就寫入了class文件當(dāng)中梧躺。簡單的理解似谁,可以將它理解為一個(gè)對象數(shù)組傲绣,而里面按照索引0到length-1分別對應(yīng)于每一個(gè)局部變量,特別的巩踏,如果是實(shí)例方法的局部變量表秃诵,第0個(gè)局部變量會是一個(gè)指向當(dāng)前實(shí)例的引用,也就是this關(guān)鍵字塞琼,其余的局部變量則從索引1開始菠净。
  • 操作數(shù)棧:它是一個(gè)后進(jìn)先出(LIFO)棧,而它的長度也是在編譯時(shí)期就寫入了class文件當(dāng)中彪杉,是固定的毅往。它的作用就是提供字節(jié)碼指令操作變量計(jì)算的空間,比如簡單的派近,對于int a=9這句話來說攀唯,就需要先將9壓入操作數(shù)棧,再將9賦給a這個(gè)變量渴丸。

在Java虛擬機(jī)規(guī)范中侯嘀,對這個(gè)區(qū)域規(guī)定了兩種異常狀況:如果線程請求的棧深度大于虛擬機(jī)所允許的深度,將拋出StackOverflowError異常谱轨;如果虛擬機(jī)椊溽#可以動(dòng)態(tài)擴(kuò)展(當(dāng)前大部分的Java虛擬機(jī)都可動(dòng)態(tài)擴(kuò)展,只不過Java虛擬機(jī)規(guī)范中也允許固定長度的虛擬機(jī)棧)土童,當(dāng)擴(kuò)展時(shí)無法申請到足夠的內(nèi)存時(shí)會拋出OutOfMemoryError異常诗茎。

本地方法棧(Native Method Stack)

本地方法棧(Native Method Stacks)與虛擬機(jī)棧所發(fā)揮的作用是非常相似的,其區(qū)別不過是虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java方法(也就是字節(jié)碼)服務(wù)娜扇,而本地方法棧則是為虛擬機(jī)使用到的Native方法服務(wù)错沃。

native方法稱為本地方法。在java源程序中以關(guān)鍵字“native”聲明雀瓢,不提供函數(shù)體枢析。
其實(shí)現(xiàn)使用C/C++語言在另外的文件中編寫,編寫的規(guī)則遵循Java本地接口的規(guī)范(簡稱JNI)刃麸。
簡而言就是Java中聲明的可調(diào)用的使用C/C++實(shí)現(xiàn)的方法醒叁。

虛擬機(jī)規(guī)范中對本地方法棧中的方法使用的語言、使用方式與數(shù)據(jù)結(jié)構(gòu)并沒有強(qiáng)制規(guī)定泊业,因此具體的虛擬機(jī)可以自由實(shí)現(xiàn)它把沼。甚至有的虛擬機(jī)(譬如Sun HotSpot虛擬機(jī))直接就把本地方法棧和虛擬機(jī)棧合二為一。與虛擬機(jī)棧一樣吁伺,本地方法棧區(qū)域也會拋出StackOverflowError和OutOfMemoryError異常饮睬。

控制參數(shù)

最后通過一張圖來了解如何通過參數(shù)來控制各區(qū)域的內(nèi)存大小

jvm04.png

-Xms設(shè)置java堆的最小空間
-Xmx設(shè)置java堆的最大空間
-XX:NewSize設(shè)置新生代最小空間
-XX:MaxNewSize設(shè)置新生代最大空間
-XX:PermSize設(shè)置永久代(方法區(qū))最小空間
-XX:MaxPermSize設(shè)置永久代(方法區(qū))最大空間
-Xss設(shè)置每個(gè)線程的堆棧大小
老年代(Old Generation)大小:java堆大小-年輕代空間大小

本文中的JVM有關(guān)問題篮奄,歡迎溝通交流哦捆愁。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末割去,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子昼丑,更是在濱河造成了極大的恐慌呻逆,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件菩帝,死亡現(xiàn)場離奇詭異咖城,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)呼奢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門宜雀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人控妻,你說我怎么就攤上這事州袒。” “怎么了弓候?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長他匪。 經(jīng)常有香客問我菇存,道長,這世上最難降的妖魔是什么邦蜜? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任依鸥,我火速辦了婚禮,結(jié)果婚禮上悼沈,老公的妹妹穿的比我還像新娘贱迟。我一直安慰自己,他們只是感情好絮供,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布衣吠。 她就那樣靜靜地躺著,像睡著了一般壤靶。 火紅的嫁衣襯著肌膚如雪缚俏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天贮乳,我揣著相機(jī)與錄音忧换,去河邊找鬼。 笑死向拆,一個(gè)胖子當(dāng)著我的面吹牛亚茬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播浓恳,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼刹缝,長吁一口氣:“原來是場噩夢啊……” “哼碗暗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起赞草,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤讹堤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后厨疙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體洲守,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年沾凄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了梗醇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡撒蟀,死狀恐怖叙谨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情保屯,我是刑警寧澤手负,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站姑尺,受9級特大地震影響竟终,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜切蟋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一统捶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柄粹,春花似錦喘鸟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至旺入,卻和暖如春兑凿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背茵瘾。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工礼华, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拗秘。 一個(gè)月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓圣絮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親雕旨。 傳聞我的和親對象是個(gè)殘疾皇子扮匠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評論 2 348

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

  • JVM內(nèi)存模型Java虛擬機(jī)(Java Virtual Machine=JVM)的內(nèi)存空間分為五個(gè)部分捧请,分別是: ...
    光劍書架上的書閱讀 2,491評論 2 26
  • 內(nèi)存溢出和內(nèi)存泄漏的區(qū)別 內(nèi)存溢出:out of memory,是指程序在申請內(nèi)存時(shí)棒搜,沒有足夠的內(nèi)存空間供其使用疹蛉,...
    Aimerwhy閱讀 732評論 0 1
  • 最近常常看到一些給學(xué)生黨推薦的平價(jià)某寶店鋪的文章力麸】煽睿可是,當(dāng)我點(diǎn)進(jìn)去克蚂,卻發(fā)現(xiàn)里面的東西也真不便宜闺鲸。(當(dāng)然啦,大家的...
    Miss夏小姐閱讀 914評論 0 14
  • 落日照大旗,馬鳴風(fēng)蕭蕭赤屋。 開闊的場景立镶,蒼涼的意境,為我們勾勒出一副英雄鐵血的畫卷类早。 初讀《大旗英雄傳》便愛上了鐵中...
    小潘安的武俠閱讀 517評論 10 3
  • 原諒我再不能追趕你的影子莺奔, 這次是真的分道揚(yáng)鑣,不能也不愿再遷就变泄。 因?yàn)槟氵@次要去雨里令哟,而我這次要去天晴。
    木土有阿杜閱讀 187評論 6 2