HotSpot 虛擬機(jī)對(duì)象探秘

一庇楞、對(duì)象的創(chuàng)建過程

當(dāng)虛擬機(jī)遇到一條new 指令時(shí):

  1. 檢查
  • 首先將去檢查這個(gè)指令的參數(shù)是否能在常量池中定位到一個(gè)類的符號(hào)引用,并且檢查這個(gè)符合引用代表的類是否已被加載极祸、解析和初始化過慈格。如果沒有,那必須先執(zhí)行相應(yīng)的類加載過程
  1. 分配內(nèi)存
  • 在類加載檢查通過后遥金,接下來虛擬機(jī)將為新生對(duì)象分配內(nèi)存浴捆。對(duì)象所需內(nèi)存的大小在類加載完成后便可確定,為對(duì)象分配空間的任務(wù)等同于把一塊確定大小的內(nèi)存從Java 堆中劃分出來稿械。
    • 指針碰撞: 假如Java 堆中內(nèi)存是絕對(duì)規(guī)整的选泻,那所分配內(nèi)存就僅僅是把那個(gè)指針向空閑空間那邊挪動(dòng)一段與對(duì)象大小相等的距離,這種分配方式稱為“指針碰撞”

    • 空閑列表:如果Java 堆中的內(nèi)存并不是規(guī)整的美莫,虛擬機(jī)就必須維護(hù)一個(gè)列表页眯,記錄上哪些內(nèi)存塊是可用的,在分配的時(shí)候從列表中找到一塊足夠大的空間劃分給對(duì)象的實(shí)例茂嗓,并更新列表上的記錄餐茵,這種分配方式被稱為“空閑列表”

      選擇哪種分配方式由Java 堆是否規(guī)整決定,而Java 堆是否規(guī)整又由所采用的垃圾收集器是否帶有壓縮整理功能決定述吸。

  • 并發(fā)情況下線程安全:
    • 虛擬機(jī)采用CAS配上失敗重試的方式保證更新操作的原子性
    • 把內(nèi)存分配的動(dòng)作按照線程劃分在不同的空間這中進(jìn)行忿族,即每個(gè)線程在Java 堆中預(yù)先分配一小塊內(nèi)存,稱為本地線程分配緩沖(Thread Local Allocation Buffer,TLAB)蝌矛。哪個(gè)線程分配內(nèi)存道批,就在哪個(gè)線程的TLAB 上分配,只有TLAB用完并分配新的TLAB時(shí)入撒,才需要同步鎖定隆豹。虛擬機(jī)是否使用TLAB,可以通過-XX:+/-UseTLAB 參數(shù)設(shè)定
  1. 初始化零值
  • 虛擬機(jī)需要將分配到的內(nèi)存空間都初始化零值(不包括對(duì)象頭)茅逮,如果使用TLAB璃赡,這一工作過程也可以提前至TLAB 分配時(shí)進(jìn)行判哥。這一步操作保證了對(duì)象的實(shí)例字段在Java 代碼中可以不賦初值諒直接使用,程序能訪問到這些字段的數(shù)據(jù)類型所對(duì)應(yīng)的零值碉考。
  1. 設(shè)置對(duì)象頭
  • 虛擬機(jī)要對(duì)對(duì)象進(jìn)行必要的設(shè)置塌计,例如這個(gè)對(duì)象是哪個(gè)類的實(shí)例、如何才能找到類的元數(shù)據(jù)信息侯谁、對(duì)象的哈希碼锌仅、對(duì)象的 GC 分代年齡等信息。這些信息存放在對(duì)象的對(duì)象頭(Object Header)這中墙贱。根據(jù)虛擬機(jī)當(dāng)前的運(yùn)行狀態(tài)的不同热芹,如是否啟用偏向鎖等,對(duì)象頭會(huì)有不同的設(shè)置方式惨撇。
  1. 執(zhí)行init 方法伊脓。
  • 從虛擬機(jī)角度來看,一個(gè)新的對(duì)象已經(jīng)產(chǎn)生了串纺,但從 Java 程序的視角來看丽旅,對(duì)象創(chuàng)建才剛剛開始——<init>方法還沒有執(zhí)行纺棺,所有的字段都還為零。所以邪狞,一般來說(由字節(jié)碼中是否跟隨 invokespecial 指令所決定)祷蝌,執(zhí)行 new 指令之后會(huì)接著執(zhí)行<init>方法,把對(duì)象按照程序員的意愿進(jìn)行初始化帆卓,這樣一個(gè)真正可用的對(duì)象才算安全產(chǎn)生出來巨朦。

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

? ? 在 HotSpot 虛擬機(jī)中剑令,對(duì)象在內(nèi)存中存儲(chǔ)的布局可以分為 3 塊區(qū)域:對(duì)象頭(Header)糊啡、實(shí)例數(shù)據(jù)(Instance Data)和對(duì)齊填充(Padding)。

  1. 對(duì)象頭(Header)

? ? HotSpot 虛擬機(jī)的對(duì)象頭包括兩部分信息:

  • 第一部分用于存儲(chǔ)對(duì)象自身的運(yùn)行時(shí)數(shù)據(jù)

? ? 存儲(chǔ)如哈希碼(HashCode)吁津、GC 分代年齡棚蓄、鎖狀態(tài)標(biāo)志、線程持有的鎖碍脏、偏向線程ID梭依、偏向時(shí)間戳等,這部分?jǐn)?shù)據(jù)的長(zhǎng)度在32位和64位的虛擬機(jī)(未開啟壓縮指針)中分別為 32bit 和 64bit典尾,官方稱為“Mark Word”.

  • 另外一部分是類型指針

??類型指針即對(duì)象指向它的類元數(shù)據(jù)的指針役拴,虛擬機(jī)通過這個(gè)指針來確定這個(gè)對(duì)象是哪個(gè)類的實(shí)例。

  1. 實(shí)例數(shù)據(jù)(Instance Data)

??實(shí)例數(shù)據(jù)部分是對(duì)象真正存儲(chǔ)的有效信息钾埂,也是在程序代碼中所定義的各種類型的字段內(nèi)容河闰。無論是從父類繼承下來的科平,還是子類中定義的,都需要記錄起來姜性。這部分的存儲(chǔ)順序會(huì)受到虛擬機(jī)分配策略參數(shù)(FieldsAllocationStyle)的字段在 Java 源碼中定義順序的影響瞪慧。HotSpot 虛擬機(jī)默認(rèn)的分配策略為 longs/doubles、ints污抬、shorts/chars汞贸、bytes/booleans、oops(Ordinary Object Pointers)印机,從分配策略中可以看出矢腻,相同寬度的字段總是被分配到一起。在滿足這個(gè)前提條件的情況下射赛,在父類中定義的變量會(huì)出現(xiàn)在子類之前多柑。如果 CompactFields 參數(shù)值為true(默認(rèn)為true),那么子類之中較窄的變量也可能會(huì)插入到父類變量的空隙之中楣责。

  1. 對(duì)齊填充(Padding)

??對(duì)齊填充并不是必然存在的竣灌,也沒有特別的含義,它僅僅起著占位符的作用由于 HotSpot VM 的自動(dòng)內(nèi)存管理系統(tǒng)要求對(duì)象起始地址必須是 8 字節(jié)的整數(shù)倍秆麸。當(dāng)對(duì)象實(shí)例數(shù)據(jù)部分沒有對(duì)齊時(shí)初嘹,就需要通過對(duì)齊填充來補(bǔ)全。

三沮趣、對(duì)象的訪問定位

??Java 程序需要通過棧上的 reference 數(shù)據(jù)來操作堆上的具體對(duì)象屯烦。目前主流的訪問方式有使用句柄和直接指針兩種。

  • 如果使用句柄訪問的話房铭,那么 Java 堆中將會(huì)劃出一塊內(nèi)存來作為句柄池,reference 中存儲(chǔ)的就是對(duì)象的句柄地址驻龟,而句柄中包含了對(duì)象實(shí)例數(shù)據(jù)與類型數(shù)據(jù)各自的具體地址信息。

    • 優(yōu)勢(shì):reference 中存儲(chǔ)的是穩(wěn)定的句柄地址缸匪,在對(duì)象被移動(dòng)(垃圾收集時(shí)移動(dòng)對(duì)象是非常普遍的行為)時(shí)只會(huì)改句柄中的實(shí)例數(shù)據(jù)指針翁狐,而 reference 本身不需要修改。
  • 如果使用直接指針訪問凌蔬,那么 Java 堆對(duì)象的布局中就必須考慮如何放置訪問類型數(shù)據(jù)的相關(guān)信息露懒,而 reference 中存儲(chǔ)的直接就是對(duì)象地址。

    • 優(yōu)勢(shì):直接指針訪問方式的最大好處就是速度更快龟梦,它節(jié)省了一次指針定位的時(shí)間開銷隐锭,由于對(duì)象的訪問在 Java 中非常繁重,因此這類開銷積少成多后也是一項(xiàng)非臣品。可觀的執(zhí)行成來钦睡。

Sun HotSpot 是使用直接指針方式進(jìn)行對(duì)象訪問的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末躁倒,一起剝皮案震驚了整個(gè)濱河市荞怒,隨后出現(xiàn)的幾起案子洒琢,更是在濱河造成了極大的恐慌,老刑警劉巖褐桌,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衰抑,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡荧嵌,警方通過查閱死者的電腦和手機(jī)呛踊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來啦撮,“玉大人谭网,你說我怎么就攤上這事≡叽海” “怎么了愉择?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)织中。 經(jīng)常有香客問我锥涕,道長(zhǎng),這世上最難降的妖魔是什么狭吼? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任层坠,我火速辦了婚禮,結(jié)果婚禮上刁笙,老公的妹妹穿的比我還像新娘窿春。我一直安慰自己,他們只是感情好采盒,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蔚润,像睡著了一般磅氨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嫡纠,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天烦租,我揣著相機(jī)與錄音,去河邊找鬼除盏。 笑死叉橱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的者蠕。 我是一名探鬼主播窃祝,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼踱侣!你這毒婦竟也來了粪小?” 一聲冷哼從身側(cè)響起大磺,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎探膊,沒想到半個(gè)月后杠愧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡逞壁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年流济,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腌闯。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绳瘟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绑嘹,到底是詐尸還是另有隱情稽荧,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布工腋,位于F島的核電站姨丈,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏擅腰。R本人自食惡果不足惜蟋恬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望趁冈。 院中可真熱鬧歼争,春花似錦、人聲如沸渗勘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽旺坠。三九已至乔遮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間取刃,已是汗流浹背蹋肮。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留璧疗,地道東北人坯辩。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像崩侠,于是被迫代替她去往敵國(guó)和親漆魔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

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