Java運行時內(nèi)存區(qū)域

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

Java虛擬機在執(zhí)行Java程序的過程中會把它所管理的內(nèi)存劃分為幾個不同的數(shù)據(jù)區(qū)域曙寡,這些區(qū)域都有各自的用途坑匠,以及創(chuàng)建和銷毀的時間毅弧,有的區(qū)域隨著虛擬機進程的啟動而存在蔫仙,有的區(qū)域則依賴用戶線程的啟動和結(jié)束而建立和銷毀鲸伴。


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

1. 程序計數(shù)器
程序計數(shù)器是一塊較小的內(nèi)存空間澜沟,它可以看作是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器灾票。字節(jié)碼解釋器工作時通過改變這個計數(shù)器的值來選擇下一條需要執(zhí)行的字節(jié)碼指令,分支茫虽、循環(huán)刊苍、跳轉(zhuǎn)既们、異常處理、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個計數(shù)器來完成班缰。
每個線程都需要一個獨立的程序計數(shù)器贤壁,用來保證線程切換后能恢復(fù)到正確的執(zhí)行位置。因此埠忘,程序計數(shù)器是線程私有的脾拆。

2. Java虛擬機棧
Java虛擬機棧也是線程私有的,它的生命周期與線程相同莹妒,它描述的是Java方法執(zhí)行的內(nèi)存模型:每個方法在執(zhí)行的同時都會創(chuàng)建一個棧幀(Stack Frame)用于存儲局部變量表名船、操作數(shù)棧、動態(tài)鏈接旨怠、方法出口等信息渠驼。
每個方法從調(diào)用直至執(zhí)行完成的過程,就對應(yīng)著一個棧幀在虛擬機棧中入棧到出棧的過程鉴腻。

  • 局部變量表存放了編譯期可知的各種基本數(shù)據(jù)類型(boolean迷扇、byte、char爽哎、short蜓席、int、float课锌、long厨内、double)、對象引用渺贤、returnAddress類型雏胃。
  • 64位長度的long和double類型的數(shù)據(jù)會占用2個局部變量空間(Slot),其余的數(shù)據(jù)類型只占用1個志鞍。
  • 局部變量表所需的內(nèi)存空間在編譯期間完成分配瞭亮,當(dāng)進入一個方法時,這個方法需要在棧幀中分配多大的局部變量空間是完全確定的固棚,在方法運行期間不會改變局部變量表的大小街州。

3. 本地方法棧
本地方法棧同Java虛擬機棧的作用相似,Java虛擬機棧為Java方法服務(wù)玻孟,而本地方法棧為虛擬機使用到的Native方法服務(wù)唆缴。

4. Java堆
Java堆是被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機啟動時創(chuàng)建黍翎。此內(nèi)存區(qū)域的唯一目的就是存放對象實例面徽,幾乎所有的對象實例都在堆上分配。
Java堆是垃圾收集器管理的主要區(qū)域,也被稱作“GC堆”趟紊。Java堆可以處于物理上不連續(xù)的內(nèi)存空間中氮双,只要邏輯上是連續(xù)的就行。

  • 從內(nèi)存回收的角度來看霎匈,由于現(xiàn)在收集器基本都采用分代收集算法戴差,Java堆還可細(xì)分為:新生代和老年代;更細(xì)致一點可分為Eden空間铛嘱、From Survivor空間暖释、To Survivor空間等。
  • 從內(nèi)存分配的角度來看墨吓,線程共享的Java堆中可劃分出多個線程私有的分配緩沖區(qū)(Thread Local Allocation Buffer球匕,TLAB)。
    劃分的目的是為了更好地回收內(nèi)存帖烘,或者更快地分配內(nèi)存亮曹。

5. 方法區(qū)
方法區(qū)也是各個線程共享的內(nèi)存區(qū)域,用于存儲已被虛擬機加載的類信息秘症、常量照卦、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù)乡摹。
Java虛擬機規(guī)范把方法區(qū)描述為堆的一個邏輯部分役耕,但它的目的同Java堆是不同的。
方法區(qū)內(nèi)存回收的目標(biāo)主要是針對常量池的回收和對類型的卸載趟卸,回收的條件相當(dāng)苛刻蹄葱,但卻十分必要氏义。

運行時常量池是方法區(qū)的一部分锄列。Class文件中除了有類的版本、字段惯悠、方法邻邮、接口等描述信息外,還有常量池克婶,它用于存放編譯期生成的各種字面量和符號引用筒严,這部分內(nèi)容將在類加載后進入方法區(qū)的運行時常量池中存放。
一般來說情萤,除了保存Class文件中描述的符號引用外鸭蛙,還會把翻譯出來的直接引用也存儲在運行時常量池中。
運行時常量池相對于Class文件常量池的另外一個重要特征是具備動態(tài)性筋岛,運行期間產(chǎn)生的新的常量也可以放入池中娶视。

二. HotSpot虛擬機對象探秘

1. 對象的創(chuàng)建
(1) 確認(rèn)對象是否加載
虛擬機遇到new指令時,首先去檢查這個指令的參數(shù)是否能在常量池中定位到一個類的符號引用,并檢查這個符號引用代表的類是否已被加載肪获、解析寝凌、初始化過。如果沒有孝赫,必須先執(zhí)行相應(yīng)的類加載過程较木。

(2) 給新對象分配內(nèi)存
類加載檢查通過后,虛擬機將為新生對象分配內(nèi)存青柄。對象所需內(nèi)存的大小在類加載完成后便可完全確定伐债,為對象分配內(nèi)存的任務(wù)等同于把一塊確定大小的內(nèi)存從Java堆中劃分出來。
給新對象分配內(nèi)存的方法有兩種:指針碰撞法空閑列表法刹前。
對象創(chuàng)建在虛擬機中是非常頻繁的行為泳赋,要保證其在并發(fā)下的安全性。

(3)默認(rèn)初始化
內(nèi)存分配完成后喇喉,虛擬機需要將分配到的內(nèi)存空間都初始化為零值(不包括對象頭)祖今,默認(rèn)初始化的操作可以保證對象的實例字段在Java代碼中可以不賦初始值就可直接使用,程序能訪問到這些字段的數(shù)據(jù)類型所對應(yīng)的零值拣技。這也是虛擬機提供的一種最低限度的安全性保證千诬。

(4)對對象進行必要的設(shè)置
接著,虛擬機對對象進行必要的設(shè)置膏斤,如這個新對象是哪個類的實例徐绑、如何才能找到類的元數(shù)據(jù)信息、對象的哈希碼莫辨、對象的GC分代年齡等信息傲茄。這些信息存放在對象的對象頭(Object Header)中。根據(jù)虛擬機當(dāng)前的運行狀態(tài)的不同沮榜,如是否啟用偏向鎖等盘榨,對象頭會有不同的設(shè)置方式。

(5)執(zhí)行構(gòu)造器中的初始化
執(zhí)行完上述動作后蟆融,從虛擬機的視角來看草巡,一個新的對象已經(jīng)產(chǎn)生了,但從Java程序的視角來看型酥,對象創(chuàng)建才剛剛開始山憨,<init>方法還沒有執(zhí)行,所有的字段都還為零弥喉。
一般來講郁竟,執(zhí)行new指令之后對接著執(zhí)行<init>方法,把對象按照程序員的意愿進行初始化由境,這樣一個真正可用的對象才算完全創(chuàng)建出來棚亩。

2. 對象的內(nèi)存布局
在HotSpot虛擬機中,對象在內(nèi)存中存儲的布局可以分為3塊區(qū)域:對象頭、實例數(shù)據(jù)蔑舞、對齊填充拒担。
HotSpot虛擬機的對象頭包括兩部分信息:
一部分用于存儲對象自身的運行時數(shù)據(jù),如哈希碼攻询、GC分代年齡从撼、鎖狀態(tài)標(biāo)志、線程持有的鎖钧栖、偏向線程ID低零、偏向時間戳等;
另一部分是類型信息拯杠,即對象指向它的類元數(shù)據(jù)的指針掏婶,虛擬機通過這個指針來確定這個對象是哪個類的實例。

實例數(shù)據(jù)部分是對象真正存儲的有效信息潭陪,也是在程序代碼中所定義的各種類型的字段內(nèi)容雄妥。無論是從父類繼承下來的,還是在子類中定義的依溯,都需要記錄下來老厌。一般情況,相同寬度的字段總是被分配到一起黎炉。在滿足這個前提條件的情況下枝秤,在父類中定義的變量會出現(xiàn)在子類之前。

對齊填充并不是必然存在的慷嗜,也沒有特別的含義淀弹,它僅僅起占位符的作用。由于HotSpot VM的自動內(nèi)存管理系統(tǒng)要求對象起始地址必須是8字節(jié)的整數(shù)倍庆械,而對象頭部分正好是8字節(jié)的倍數(shù)薇溃,如果對象實例數(shù)據(jù)部分沒有對齊時,就需要通過對齊填充來補全干奢。

3. 對象的訪問定位
創(chuàng)建對象的目的是為了使用對象痊焊,Java程序需要通過棧上的reference數(shù)據(jù)來操作堆上的具體對象盏袄。目前主流的對象訪問方式有兩種:使用句柄直接指針忿峻。
(1)使用句柄:在Java堆中劃分出一塊內(nèi)存來作為句柄池,reference中存儲的就是對象的句柄地址辕羽,句柄中包含了對象實例數(shù)據(jù)與類型數(shù)據(jù)各自的具體地址信息逛尚。

使用句柄訪問對象

(2)直接指針:reference中存儲的直接就是對象地址。

使用指針訪問對象

使用句柄訪問好處就是reference中存儲的是穩(wěn)定的句柄地址刁愿,在對象被移動時只會改變句柄中的實例數(shù)據(jù)指針绰寞,而reference本身不需要修改。
使用指針訪問的好處就是速度更快,它節(jié)省了一次指針定位的時間開銷滤钱。
HotSpot采用直接指針的方式進行對象的訪問觉壶。

網(wǎng)絡(luò)上看到一張整理的比較好的圖片,引用如下:


JVM內(nèi)存管理
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末件缸,一起剝皮案震驚了整個濱河市铜靶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌他炊,老刑警劉巖争剿,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異痊末,居然都是意外死亡蚕苇,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門凿叠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涩笤,“玉大人,你說我怎么就攤上這事盒件×舅” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵履恩,是天一觀的道長锰茉。 經(jīng)常有香客問我,道長切心,這世上最難降的妖魔是什么飒筑? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮绽昏,結(jié)果婚禮上协屡,老公的妹妹穿的比我還像新娘。我一直安慰自己全谤,他們只是感情好肤晓,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著认然,像睡著了一般补憾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卷员,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天盈匾,我揣著相機與錄音,去河邊找鬼毕骡。 笑死削饵,一個胖子當(dāng)著我的面吹牛岩瘦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播窿撬,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼启昧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了劈伴?” 一聲冷哼從身側(cè)響起箫津,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宰啦,沒想到半個月后苏遥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡赡模,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年田炭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漓柑。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡教硫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出辆布,到底是詐尸還是另有隱情瞬矩,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布锋玲,位于F島的核電站景用,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏惭蹂。R本人自食惡果不足惜伞插,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望盾碗。 院中可真熱鬧媚污,春花似錦、人聲如沸廷雅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽航缀。三九已至商架,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谬盐,已是汗流浹背甸私。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工诚些, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留飞傀,地道東北人皇型。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像砸烦,于是被迫代替她去往敵國和親弃鸦。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

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