JVM運行時數(shù)據(jù)區(qū)域

對于初學(xué)者來說谱邪,Java虛擬機就像一堆高墻领追,它用內(nèi)存動態(tài)分配和垃圾回收技術(shù)組成,隔離了Java和C的內(nèi)存管理的工作。今天就來一探究竟望蜡,一起翻越這堵高墻唤崭。


城墻

起因

相信很多童鞋都是只在學(xué)校里學(xué)過C、C++脖律,幾乎沒有接觸過Java谢肾。在使用C系列編程的時候,開發(fā)人員不得不自己去做對象內(nèi)存空間的申請和回收小泉,我們擁有無限大的權(quán)限芦疏,我們可以是“皇帝”,也同樣是每一個對象的“保姆”->負責(zé)每個對象的生命經(jīng)常的全部微姊。

Java的世界里酸茴,將這一切都屏蔽掉了,它底層使用一個叫虛擬機的東西自己實現(xiàn)了內(nèi)存的管理兢交。不用再寫alloc 和 free 這樣的函數(shù)了薪捍,不用日出現(xiàn)內(nèi)存泄露的問題。這一切看起來那么美好配喳,但是....正是因為這一切那么輕松酪穿,當(dāng)真正出現(xiàn)內(nèi)存泄露和溢出方面的問題的時候,如果我們不深入了解虛擬機是如何運作的晴裹、如果管理內(nèi)存的被济,那么一切都變成災(zāi)難!

示意圖

Java虛擬機在執(zhí)行Java程序的過程中會把它管理的內(nèi)存劃分為若干個不同的數(shù)據(jù)區(qū)域涧团。這些區(qū)域都有各自的用途只磷,根據(jù)Java虛擬機規(guī)范的規(guī)定,虛擬機所管理內(nèi)存會被分為如下圖所示的幾個區(qū)域:

JVM運行時數(shù)據(jù)區(qū)域示意圖

接下來就讓它們每個區(qū)域的區(qū)長上臺介紹下自己~~~

程序計數(shù)器

區(qū)長:其實我的地盤是比較小的少欺,其實大家可以把我看著是當(dāng)前線程所執(zhí)行的字節(jié)碼的交通信號燈喳瓣,負責(zé)控制每一條字節(jié)碼指令的執(zhí)行控制。我們這塊區(qū)域是授權(quán)唯一不會拋出OutOfMemoryError異常的區(qū)域赞别!

字節(jié)碼解釋器工作時畏陕,其實就是通過改變信號燈的值來覺得下一個同行的是哪一條字節(jié)碼指令,分支仿滔、循環(huán)惠毁、跳轉(zhuǎn)、異常處理崎页、線程恢復(fù)等基礎(chǔ)功能都會依賴這個計數(shù)器完成鞠绰。

Java虛擬機的多線程內(nèi)部是通過線程輪流切換并分配CPU執(zhí)行時間的方式實現(xiàn)的,在任何一個確定的時刻飒焦,一個處理器都只會執(zhí)行一個線程鐘的指令蜈膨。那么當(dāng)線程切換后能恢復(fù)到上一次的位置屿笼,每個線程都需要一個獨立的程序計數(shù)器,各個線程之間互不干擾翁巍,這類線程共享的內(nèi)存區(qū)域稱為“線程私有”內(nèi)存驴一。

更多內(nèi)容:如果線程當(dāng)前執(zhí)行的是一個java方法,那么計數(shù)器記錄的是正在執(zhí)行的虛擬機字節(jié)碼命令的地址灶壶;如果是native的方法肝断,那計數(shù)器則為Undefined。

Java虛擬機棧

從示意圖我們可以看出來驰凛,這塊區(qū)域也是被劃為線程私有內(nèi)存區(qū)域胸懈,當(dāng)線程結(jié)束的時候,這塊區(qū)域也就壽盡終寢啦恰响。虛擬機棧其實描述的正是Java方法執(zhí)行的內(nèi)存模型:每個方法在執(zhí)行的同事都會創(chuàng)建一個棧幀(Stack Frame)用于存儲局部變量趣钱、操作數(shù)、動態(tài)鏈接渔隶、方法出口這些信息羔挡。每一個方法從調(diào)用->執(zhí)行->返回的過程與棧幀在虛擬機棧中入棧到出棧的過程對應(yīng)。

Java虛擬機棧示意圖

幀棧結(jié)構(gòu)
局部變量表存放了編譯器可知的各種基本數(shù)據(jù)類型(boolean间唉、byte、char利术、short呈野、int、float印叁、long被冒、double)、對象引用(reference類型轮蜕,它不等同于對象本身昨悼,可能是指向一個代表對象的句柄或者其他與此對象相關(guān)的變量)和retureAddress類型。其中64位長度的long和double類型的數(shù)據(jù)會占2個局部變量空間跃洛,其余的數(shù)據(jù)類型只占1個率触。

局部變量表所需的內(nèi)存空間是在編譯期完成分配,當(dāng)進入一個方法時汇竭,這個方法需要在幀中分配多大的局部變量空間是完全確定的葱蝗,在方法運行期不會改變局部變量表的大小。

規(guī)范中定義了兩種異常:

  • 如果線程的請求的棧深度大于虛擬機允許的深度细燎,將會拋出StackOverflowError異常
  • 如果虛擬機棧動態(tài)可擴展两曼,當(dāng)擴展到無法申請到足夠內(nèi)存時,就會拋出OutOfMemoryError異常

本地方法棧

這塊內(nèi)存區(qū)域和虛擬機棧非常相似玻驻,他們的區(qū)別從名字就可以看出來:Java虛擬機棧是用來執(zhí)行Java方法的悼凑,而本地方法棧是用來執(zhí)行Native方法的。

Sun HotSpot 合并了虛擬機棧和本地方法棧

Java堆

Java堆應(yīng)該是虛擬機管轄范圍內(nèi)最大的一塊內(nèi)存區(qū)域。這塊區(qū)域是被所有線程共享户辫,在虛擬機一啟動的時候就創(chuàng)建的渐夸,它的唯一目的就是存放對象實例,幾乎所有對象的實例都需要到這里申請內(nèi)存寸莫。

規(guī)范中描述:所有的對象實例以及數(shù)組都要在堆上分配捺萌,但是隨著JIT編譯器和逃逸分析技術(shù)的成熟,棧上分配膘茎、標(biāo)量替換這些技術(shù)會導(dǎo)致一些微妙的變化桃纯,前面的“所有”會變得不那么絕對。

Java堆是垃圾回收期(GC)管理的主要區(qū)域披坏,從內(nèi)存回收的角度來看态坦,現(xiàn)代的收集器都采用分代收集算法,所有這塊區(qū)域又會細分為好幾個區(qū)域:新生代棒拂、老年代伞梯;再細節(jié)的又會分為 Eden、From Survivor帚屉、To Survivor谜诫,下圖展示了詳細的區(qū)域:

Java堆內(nèi)存示意圖

從內(nèi)存分配的角度來看,線程共享的Java堆中可能劃分出多個線程私有的分配緩沖區(qū)攻旦。但是不管怎么劃分喻旷,都與它存放的內(nèi)容(對象實例)無關(guān),都是為了更好地管理這塊區(qū)域牢屋,進行內(nèi)存回收且预、更快分配內(nèi)存

規(guī)范中規(guī)定烙无,Java堆的內(nèi)存可以不保證空間連續(xù)锋谐,只需要保證邏輯連續(xù)即可。所以我們在實際生產(chǎn)中經(jīng)常講-Xmx和-Xms寫成一致的截酷,這樣來減低因為動態(tài)擴展帶來的不可預(yù)見情況

方法區(qū)

這塊區(qū)域在java8中已經(jīng)被換成元空間涮拗,詳情見JAVA8:從永久區(qū)PermGen到元空間Metaspace

方法區(qū)和Java堆一樣,都是所有線程共享的一塊內(nèi)存區(qū)域合搅,它用于存儲已被虛擬機加載的類信息多搀、常量、靜態(tài)變量灾部、即時編譯器編譯后的代碼等數(shù)據(jù)康铭。另外它有一個別名叫著“永久代”,這是因為HotSpot虛擬機將GC分代收集擴展到了方法區(qū)赌髓,這樣HotSpot的垃圾回收器就可以一同樣的方式來管理這塊內(nèi)存从藤。而這塊區(qū)域會因為極少數(shù)情況(深入理解 Java String#intern() 內(nèi)存模型)出現(xiàn)異常

運行時常量池
這部分也是方法區(qū)的一部分催跪,Class文件中除了有類的版本號、字段夷野、方法懊蒸、接口等描述信息外,還有一項信息是常量池悯搔,用于存放編譯期生成的各種字面量和符號引用骑丸,這部分內(nèi)容將在類加載后進入方法去的運行時常量池中存放。

直接內(nèi)存

這塊區(qū)域在上面的示意圖中看不到妒貌,是因為這塊內(nèi)存其實不受虛擬機管理通危,當(dāng)時這部分內(nèi)存過度使用,也會拋出OutOfMemoryError異常灌曙。

NIO中引入了一種基于通信和緩沖區(qū)的I/O方式菊碟,它可以使用Native的函數(shù)來直接分配Java堆外的內(nèi)存,然后通過一個存儲在Java堆中的一個DirectByteBuffer對象作為這塊內(nèi)存引用進行操作在刺。所以在設(shè)置虛擬機堆大小的時候需要注意逆害,如果使用了堆外內(nèi)存需要考慮公式:堆內(nèi)+堆外 < 總內(nèi)存大小。目前市面上有很多的堆外工具蚣驼,mapdb就是其中之一魄幕。應(yīng)用比較多的是堆外緩存解決使用堆內(nèi)緩存造成的fullgc頻繁問題。

青春無敵體操服妹子

參考
--

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末颖杏,一起剝皮案震驚了整個濱河市梅垄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌输玷,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件靡馁,死亡現(xiàn)場離奇詭異欲鹏,居然都是意外死亡,警方通過查閱死者的電腦和手機臭墨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門赔嚎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人胧弛,你說我怎么就攤上這事尤误。” “怎么了结缚?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵损晤,是天一觀的道長。 經(jīng)常有香客問我红竭,道長尤勋,這世上最難降的妖魔是什么喘落? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮最冰,結(jié)果婚禮上瘦棋,老公的妹妹穿的比我還像新娘。我一直安慰自己暖哨,他們只是感情好赌朋,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著篇裁,像睡著了一般沛慢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上茴恰,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天颠焦,我揣著相機與錄音,去河邊找鬼往枣。 笑死伐庭,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的分冈。 我是一名探鬼主播圾另,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼雕沉!你這毒婦竟也來了集乔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤坡椒,失蹤者是張志新(化名)和其女友劉穎扰路,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體倔叼,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡汗唱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了丈攒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哩罪。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖巡验,靈堂內(nèi)的尸體忽然破棺而出际插,到底是詐尸還是另有隱情,我是刑警寧澤显设,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布框弛,位于F島的核電站,受9級特大地震影響敷硅,放射性物質(zhì)發(fā)生泄漏功咒。R本人自食惡果不足惜愉阎,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望力奋。 院中可真熱鬧榜旦,春花似錦、人聲如沸景殷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽猿挚。三九已至咐旧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绩蜻,已是汗流浹背铣墨。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留办绝,地道東北人伊约。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像孕蝉,于是被迫代替她去往敵國和親屡律。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355

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