深入理解JVM學(xué)習(xí)筆記-Java內(nèi)存區(qū)域與內(nèi)存溢出異常

運(yùn)行時(shí)數(shù)據(jù)區(qū)域

Java虛擬機(jī)在執(zhí)行java程序的過程中會(huì)將它所管理的內(nèi)存劃分為若干不同的數(shù)據(jù)區(qū)域队伟,這些區(qū)域有各自用途闽瓢,以及創(chuàng)建和銷毀時(shí)間胁住,有的區(qū)域隨著虛擬機(jī)進(jìn)程的啟動(dòng)而存在层宫,有些區(qū)域依賴用戶線程的啟動(dòng)和結(jié)束而建立和銷毀学密。
Java虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)如下圖所示:

JVM運(yùn)行時(shí)數(shù)據(jù)區(qū).jpg

從圖中揭蜒,我們看到了5大區(qū)域:線程共享的方法區(qū)和堆横浑,線程私有的java虛擬機(jī)棧,本地方法棧以及程序計(jì)數(shù)器屉更。
程序計(jì)數(shù)器:(Program Counter Register)這個(gè)區(qū)域是唯一一個(gè)不會(huì)拋出OutOfMemoryError異常的區(qū)域徙融。它是一塊比較小的內(nèi)存,是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器瑰谜。為了線程切換后能恢復(fù)到正確的執(zhí)行位置欺冀,每條線程都需要有一個(gè)獨(dú)立的程序計(jì)算器,各條線程之間計(jì)算器互不影響萨脑。
Java虛擬機(jī)棧:也是線程私有的隐轩,它的生命周期與線程相同,它描述的是java方法執(zhí)行的內(nèi)存模型渤早,每個(gè)方法在執(zhí)行的時(shí)候會(huì)創(chuàng)建一個(gè)棧幀用來存儲(chǔ)局部變量职车,操作數(shù),動(dòng)態(tài)鏈接等。每個(gè)方法從調(diào)用直至執(zhí)行完成的過程悴灵,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中入棧和出棧的過程军援。
本地方法棧:和java虛擬機(jī)棧功能類似,只不過java虛擬機(jī)棧執(zhí)行的是java字節(jié)碼而本地方法棧執(zhí)行的是Native方法称勋。
Java堆:Java堆是虛擬機(jī)所管理的內(nèi)存中最大的一塊,Java堆是被所有線程共享的一塊內(nèi)存區(qū)域涯竟,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存赡鲜。java堆可以細(xì)分出新生代和老年代,再細(xì)致一點(diǎn)可以分為:Eden庐船,F(xiàn)rom Survivor银酬,To Survivor等空間。
方法區(qū):該區(qū)域用來存儲(chǔ)已經(jīng)被虛擬機(jī)加載過來的類信息筐钟,常量揩瞪,靜態(tài)變量等。方法區(qū)導(dǎo)致內(nèi)存問題實(shí)例請(qǐng)參考:Android性能優(yōu)化-方法區(qū)導(dǎo)致內(nèi)存問題實(shí)例分析篓冲。
以上講完了JVM運(yùn)行時(shí)內(nèi)存區(qū)域的5大塊李破,同時(shí)需要補(bǔ)充的一點(diǎn)是還有一個(gè)運(yùn)行時(shí)常量池,它也是方法區(qū)的一部分壹将。Class文件中除了有類的版本嗤攻,字段,接口诽俯,方法等描述信息外妇菱,還有一項(xiàng)信息就是常量池,用來存放編譯時(shí)期生成的各種字面量和符號(hào)引用暴区。但是需要注意的是:Java語言并不要求常量一定是在編譯期間產(chǎn)生闯团,也就是并非與裝入class文件中的常量池的內(nèi)容才能進(jìn)入到方法區(qū)運(yùn)行時(shí)常量池,運(yùn)行期間也可能將新的常量放入常量池中仙粱,如String.intern()方法房交。

運(yùn)行時(shí)不同數(shù)據(jù)區(qū)域異常

(1)除程序計(jì)算器外,虛擬機(jī)內(nèi)存的其他幾個(gè)運(yùn)行時(shí)區(qū)都會(huì)發(fā)生OutOfMemoryError伐割。
(2)使Java堆發(fā)生內(nèi)存溢出的思路:只要不斷創(chuàng)建對(duì)象涌萤,并保證GC Roots到對(duì)象之間有可達(dá)路徑來避免垃圾回收機(jī)制清除這些對(duì)象即可。
(3)使方法區(qū)發(fā)生類導(dǎo)致的內(nèi)存溢出基本思路:在運(yùn)行時(shí)產(chǎn)生大量的類去填滿方法區(qū)口猜,也就是在運(yùn)行時(shí)動(dòng)態(tài)產(chǎn)生很多的類负溪,直到方法區(qū)內(nèi)存溢出。所以頻繁動(dòng)態(tài)產(chǎn)生很多類時(shí)济炎,需要注意方法區(qū)內(nèi)存溢出川抡,具體內(nèi)容請(qǐng)參考Android性能優(yōu)化-方法區(qū)導(dǎo)致內(nèi)存問題實(shí)例分析
(4)虛擬機(jī)棧和本地方法棧兩種異常:
a) 如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的最大深度(即方法調(diào)用深度超過最大允許深度),將拋出StackOverFlowError異常.
b) 如果虛擬機(jī)在擴(kuò)展棧時(shí)無法申請(qǐng)到足夠的內(nèi)存崖堤,則拋出utOfMemoryError異常侍咱。

HotSpot虛擬機(jī)對(duì)象創(chuàng)建、對(duì)象內(nèi)存布局密幔、對(duì)象訪問定位

對(duì)象創(chuàng)建

(1)對(duì)象創(chuàng)建的幾種方法:new楔脯、克隆、反序列化胯甩;
(2)對(duì)象創(chuàng)建過程:
步驟一:虛擬機(jī)在遇到new指令時(shí)昧廷,首先會(huì)去檢查這個(gè)指令的參數(shù)是否能在常量池中定位到一個(gè)類的符號(hào)引用并且檢查該符號(hào)引用代表的類是否已經(jīng)被加載,解析和初始化過偎箫。如果沒有木柬,那就必須先執(zhí)行相應(yīng)的類加載。
步驟二:在類經(jīng)過加載檢查后淹办,虛擬機(jī)就需要為新生對(duì)象分配內(nèi)存了眉枕。對(duì)象所需要的內(nèi)存大小在類加載完成之后就可以確定。對(duì)象分配內(nèi)存空間的任務(wù)等同于把一塊確定大小的內(nèi)存從java堆中劃分出來怜森,如果內(nèi)存絕對(duì)規(guī)整速挑,采用指針碰撞分配方式(即移動(dòng)指針到與對(duì)象大小相等的距離),如果內(nèi)存不規(guī)整采用空間列表的分配方式副硅。
步驟三:在分配完內(nèi)存之后梗摇,虛擬機(jī)需要將分配到的內(nèi)存空間初始化為零值。
步驟四:接下來想许,虛擬機(jī)會(huì)對(duì)對(duì)象進(jìn)行必要的設(shè)置伶授,如對(duì)象的hash碼,對(duì)象的GC分代信息等流纹。
步驟五:最后執(zhí)行對(duì)象的init方法把對(duì)象按照程序員意愿進(jìn)行初始化糜烹,這樣一個(gè)真正的對(duì)象才算完全產(chǎn)生出來。

對(duì)象內(nèi)存布局

對(duì)象內(nèi)存布局分為三塊區(qū)域:對(duì)象頭漱凝、實(shí)例數(shù)據(jù)疮蹦、對(duì)齊填充。
對(duì)象頭:主要存儲(chǔ)了2部分信息茸炒,第一部分是對(duì)象自身運(yùn)行的數(shù)據(jù)愕乎,如hashcode,GC分代等信息壁公;
第二部分是類型指針感论,就是對(duì)象對(duì)它的類元數(shù)據(jù)指針,其實(shí)就是一個(gè)引用紊册。虛擬機(jī)通過這個(gè)指針(引用)來確定對(duì)象是哪個(gè)類的實(shí)例比肄。
實(shí)例數(shù)據(jù)(Instance Data):對(duì)象真正存儲(chǔ)的有效信息,也就是程序代碼中所寫的各種類型的字段內(nèi)容。
對(duì)齊填充(Padding):這個(gè)不是必然存在的芳绩。HotSpot虛擬機(jī)自動(dòng)內(nèi)存管理要求對(duì)象起始地址必須是8字節(jié)的整數(shù)倍掀亥,也就是對(duì)象大小必須是8字節(jié)的整數(shù)倍,對(duì)象實(shí)例數(shù)據(jù)部分沒有對(duì)齊時(shí)妥色,需要通過對(duì)齊填充來補(bǔ)齊搪花。

對(duì)象的訪問定位

我們知道了對(duì)象的創(chuàng)建,內(nèi)存布局等相關(guān)內(nèi)容之后嘹害,需要知道存儲(chǔ)的對(duì)象如何找到呢撮竿?這就涉及到對(duì)象的定位問題了。我們java程序需要通過棧上的引用數(shù)據(jù)來操作具體的對(duì)象吼拥。對(duì)對(duì)象的訪問方式取決于虛擬機(jī)的實(shí)現(xiàn),目前比較主流的有句柄和直接指針兩種方式线衫。下面讓我們看看這兩種方式吧凿可,直接上圖:


通過句柄訪問對(duì)象.jpg
通過直接指針訪問對(duì)象.jpg

第1張圖是通過句柄的方式對(duì)對(duì)象進(jìn)行訪問,在java堆中劃分出來一塊內(nèi)存作為句柄池授账,而reference中存儲(chǔ)的是對(duì)象的句柄地址枯跑,句柄中存儲(chǔ)了對(duì)象實(shí)例等信息。第2張圖是通過直接指針的方式白热,reference中存儲(chǔ)的是實(shí)例對(duì)象的地址敛助。
這兩種對(duì)象引用的方式各有千秋,通過句柄的好處是reference中存儲(chǔ)的是穩(wěn)定的句柄地址屋确,在對(duì)象被移動(dòng)的時(shí)候只會(huì)改變句柄的實(shí)例指針而reference本身不需要修改纳击;使用直接指針的好處是速度開,不需要在java堆中在劃分出一塊內(nèi)存區(qū)域同時(shí)節(jié)省了指針定位的開銷攻臀。但是就HotSpot而言焕数,采用的是直接指針方式。

通過以上內(nèi)容刨啸,我們明白了虛擬機(jī)中的內(nèi)存是如何劃分的堡赔,那部分區(qū)域,什么樣的代碼和操作可能導(dǎo)致內(nèi)存異常溢出異常设联。雖然java有垃圾收集機(jī)制善已,但是內(nèi)存溢出離我們并不遙遠(yuǎn),下一篇文章將講解Java垃圾收集機(jī)為避免內(nèi)存溢出異常的出現(xiàn)做了哪些努力离例。

以上就是Java內(nèi)存區(qū)域與內(nèi)存溢出異常相關(guān)內(nèi)容换团,大部分內(nèi)容直接從小臘月虛擬機(jī)相關(guān)文章直接拷貝而來(節(jié)省打字時(shí)間)。

JVM學(xué)習(xí)資料

《深入理解Java虛擬機(jī)》
Java虛擬機(jī)原理圖解系列文章
小臘月虛擬機(jī)相關(guān)文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宫蛆,一起剝皮案震驚了整個(gè)濱河市啥寇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖辑甜,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衰絮,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡磷醋,警方通過查閱死者的電腦和手機(jī)猫牡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來邓线,“玉大人淌友,你說我怎么就攤上這事『С拢” “怎么了震庭?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)你雌。 經(jīng)常有香客問我器联,道長(zhǎng),這世上最難降的妖魔是什么婿崭? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任拨拓,我火速辦了婚禮,結(jié)果婚禮上氓栈,老公的妹妹穿的比我還像新娘渣磷。我一直安慰自己,他們只是感情好授瘦,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布醋界。 她就那樣靜靜地躺著,像睡著了一般提完。 火紅的嫁衣襯著肌膚如雪物独。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天氯葬,我揣著相機(jī)與錄音挡篓,去河邊找鬼。 笑死帚称,一個(gè)胖子當(dāng)著我的面吹牛官研,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播闯睹,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼戏羽,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了楼吃?” 一聲冷哼從身側(cè)響起始花,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤妄讯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后酷宵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亥贸,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年浇垦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了炕置。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡男韧,死狀恐怖朴摊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情此虑,我是刑警寧澤甚纲,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站朦前,受9級(jí)特大地震影響介杆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜况既,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一这溅、第九天 我趴在偏房一處隱蔽的房頂上張望组民。 院中可真熱鬧棒仍,春花似錦、人聲如沸臭胜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舆驶。三九已至,卻和暖如春熊昌,著一層夾襖步出監(jiān)牢的瞬間仪壮,已是汗流浹背憨颠。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留积锅,地道東北人爽彤。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像缚陷,于是被迫代替她去往敵國(guó)和親适篙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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