Java對象創(chuàng)建過程詳解

本文會主要介紹對象創(chuàng)建并簡要介紹對象創(chuàng)建過程中的一些操作 虛擬機HotSpot

對象創(chuàng)建

虛擬機接受到一個new指令時

  • 首先檢查參數(shù)能否在常量池內(nèi)定位到類的符號引用轨淌,并判斷類是否已經(jīng)被加載,解析和初始化(類的加載過程見附1)
  • 接著虛擬機為對象分配內(nèi)存迄靠,分配內(nèi)存的大小在類加載完成時就已經(jīng)確定瞒窒。(分配內(nèi)存的方法見附2)
  • 內(nèi)存分配完成后,將內(nèi)存空間全部賦零值(不包括對象頭)
  • 接下來完成對對象頭的設(shè)置 包括屬于哪個類 如何找到類元數(shù)據(jù) 哈希碼 GC分代年齡等信息(對象頭詳細內(nèi)容見附3)
  • 調(diào)用對象的<init>方法 完成初始化

至此 一個完整的Java對象就被創(chuàng)建完成了

注意:多線程使用同一對象時需要注意對象創(chuàng)建時指令重排序的問題

附錄1 類加載

image

需要類初始化的五種情況(有且僅有這五種) (類的加載沒有硬性規(guī)定)

  • 遇到new getstatic putstatic invokestatic這四個指令時 如果類沒有初始化,則會觸發(fā)類的初始化兵罢。四個指令對應(yīng)的最常見的情況為使用new關(guān)鍵字實例化對象,讀取靜態(tài)變量滓窍,設(shè)置靜態(tài)變量(編譯期結(jié)果放入常量池的除外 會觸發(fā)前幾個階段) 卖词,調(diào)用類的靜態(tài)方法
  • 使用java.lang.reflect包的方法對類進行反射調(diào)用
  • 初始化一個類時 如果父類未初始化 則初始化父類
  • 虛擬機啟動時指定的主類
  • java1.7動態(tài)語言支持

常見的不會觸發(fā)初始化的引用方式

  • 通過子類引用父類的靜態(tài)變量 只會初始化父類 不會初始化子類
  • 創(chuàng)建類的數(shù)組
  • 引用常量池內(nèi)的變量

\color{red}{Q:調(diào)用類的static final對象一定不會初始化這個類嗎?如果會贰您,什么情況?}

加載

通過名字獲取類的二進制流并在內(nèi)存中生成class對象拢操。

驗證

驗證二進制流的正確性和安全性 包括文件格式驗證锦亦,元數(shù)據(jù)驗證,字節(jié)碼驗證以及符號引用驗證四個步驟令境。

準(zhǔn)備

給類變量(static)分配空間并完成初始化 注意:如果不是final變量杠园,值均為零值。

解析

將符號引用解析為直接引用舔庶,包括類或接口的解析抛蚁,字段解析,類方法解析惕橙,接口方法解析瞧甩。

初始化

執(zhí)行類的<cinit>()方法,這個方法由所有對靜態(tài)變量的賦值操作和所有靜態(tài)代碼塊組成弥鹦,虛擬機會保證父類的<cinit>()方法在子類的方法開始之前結(jié)束肚逸,并且提供線程安全的保證(類似于double check,多個線程同時初始化時只有一個線程進入方法彬坏,其他線程阻塞朦促,執(zhí)行完成后其他線程不會再進入方法)

類加載器-雙親委派模型

Java推薦的類加載器的實現(xiàn)模型,除了啟動類加載器(bootstrap classLoader)以外的所有類加載器都應(yīng)該擁有父加載器栓始,這個關(guān)系不是通過繼承來實現(xiàn)务冕,而是通過組合的方式。類加載器收到加載請求時幻赚,首先請求父加載器進行加載禀忆,如果父加載器不能加載則調(diào)用自己的加載方法。自定義類加載器時如果我們希望遵從雙親委派模型則重寫findClass()方法落恼,否則重寫loadClass()方法

類加載器-分類

遵循雙親委派從上到下可以分為

  • 啟動類加載器 (Bootstrap classLoader) 加載<JAVA_HOME>\lib下的指定文件名的類
  • 擴展類加載器 (Extension classLoader) 加載<JAVA_HOME>\lib\ext下的類
  • 系統(tǒng)類加載器(應(yīng)用類加載器) 加載Classpath內(nèi)的類
  • 自定義類加載器

不遵循雙親委派的常見類加載器:

  • SPI (Service Provider Interface)加載器 - 線程上下文加載器 實現(xiàn)父加載器向子加載器請求加載
  • OSGi模塊化加載器 每個模塊擁有一個自定義類加載器 網(wǎng)狀結(jié)構(gòu)的加載過程

附錄2 內(nèi)存的分配

1.確定對象內(nèi)存大小

對象的大小在類加載完成后就已經(jīng)確定油湖,對象在內(nèi)存中可以分為三塊

  • 對象頭(附錄三)

大小確定 與類無關(guān) 與操作系統(tǒng)有關(guān)

  • 實例數(shù)據(jù)

即使父類的實例字段被子類覆蓋或者被private修飾,都照樣為其分配內(nèi)存领跛,相同寬度的字段會分配在一起乏德,其次,父類的字段在子類之前

  • 對齊填充

滿足虛擬機對8的倍數(shù)的要求

2.分配內(nèi)存

內(nèi)存分配與內(nèi)存回收緊密相關(guān),根據(jù)不同的回收策略也有不同的分配策略喊括。

如果采用的是具有壓縮過程的垃圾回收策略胧瓜,如Serial,ParNew,則Java堆中的內(nèi)存是規(guī)整的郑什,我們只需要將內(nèi)存指針向后移內(nèi)存大小的位置即可府喳,這種方式稱為指針碰撞(Bump the Pointer)。如果采用的回收策略沒有壓縮過程蘑拯,如CMS钝满,那虛擬機就需要維護一個列表,記錄哪些內(nèi)存是可用的申窘,這種方式稱為空閑列表(Free List)

其次弯蚜,對象創(chuàng)建也需要考慮線程安全的問題,一種方案是采用CAS+失敗重試的方法來保證線程安全剃法,另一種方法則是為每一個線程提前分配一塊內(nèi)存碎捺,稱為本地線程分配緩沖(Thread Local Allocation Buffer , TLAB),線程創(chuàng)建對象時優(yōu)先在自己的TLAB上分配贷洲。

附錄3 對象頭

對象頭包括

  • MarkWord 32bit/64bit 取決于操作系統(tǒng)
  • 類型指針 指向類元數(shù)據(jù)的指針
  • 數(shù)組長度 如果是數(shù)組的話

我們主要介紹MarkWord

image

根據(jù)鎖狀態(tài)的不同收厨,markword會復(fù)用自己的空間,分別記錄一些不同的信息优构。

我們注意到 輕量級鎖和重量級鎖狀態(tài)時诵叁,會將分代年齡覆蓋掉,那當(dāng)鎖狀態(tài)解除時钦椭,要怎么恢復(fù)呢黎休?

答案是上鎖時,鎖的數(shù)據(jù)中會保存一份原markword的備份

\color{red}{Q:重量級鎖中的monitor是指什么?}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末玉凯,一起剝皮案震驚了整個濱河市势腮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌漫仆,老刑警劉巖捎拯,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異盲厌,居然都是意外死亡署照,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門吗浩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來建芙,“玉大人,你說我怎么就攤上這事懂扼〗” “怎么了右蒲?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長赶熟。 經(jīng)常有香客問我瑰妄,道長,這世上最難降的妖魔是什么映砖? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任间坐,我火速辦了婚禮,結(jié)果婚禮上邑退,老公的妹妹穿的比我還像新娘竹宋。我一直安慰自己,他們只是感情好地技,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布倒庵。 她就那樣靜靜地躺著镜会,像睡著了一般式撼。 火紅的嫁衣襯著肌膚如雪似枕。 梳的紋絲不亂的頭發(fā)上溯警,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天趣苏,我揣著相機與錄音,去河邊找鬼梯轻。 笑死食磕,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的喳挑。 我是一名探鬼主播彬伦,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼伊诵!你這毒婦竟也來了单绑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤曹宴,失蹤者是張志新(化名)和其女友劉穎搂橙,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體笛坦,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡区转,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了版扩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片废离。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖礁芦,靈堂內(nèi)的尸體忽然破棺而出蜻韭,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布湘捎,位于F島的核電站诀豁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏窥妇。R本人自食惡果不足惜舷胜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望活翩。 院中可真熱鬧烹骨,春花似錦、人聲如沸材泄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拉宗。三九已至峦树,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間旦事,已是汗流浹背魁巩。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留姐浮,地道東北人谷遂。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像卖鲤,于是被迫代替她去往敵國和親肾扰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355

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

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,103評論 1 32
  • 第二部分 自動內(nèi)存管理機制 第二章 java內(nèi)存異常與內(nèi)存溢出異常 運行數(shù)據(jù)區(qū)域 程序計數(shù)器:當(dāng)前線程所執(zhí)行的字節(jié)...
    小明oh閱讀 1,172評論 0 2
  • 一蛋逾、運行時數(shù)據(jù)區(qū)域 Java虛擬機管理的內(nèi)存包括幾個運行時數(shù)據(jù)內(nèi)存:方法區(qū)集晚、虛擬機棧、本地方法棧区匣、堆偷拔、程序計數(shù)器,...
    luhanlin閱讀 545評論 0 0
  • 一沉颂、運行時數(shù)據(jù)區(qū)域 Java虛擬機管理的內(nèi)存包括幾個運行時數(shù)據(jù)內(nèi)存:方法區(qū)条摸、虛擬機棧、本地方法棧铸屉、堆钉蒲、程序計數(shù)器,...
    加油小杜閱讀 1,519評論 1 15
  • 整理來自互聯(lián)網(wǎng) 1彻坛,JDK:Java Development Kit顷啼,java的開發(fā)和運行環(huán)境踏枣,java的開發(fā)工具...
    Ncompass閱讀 1,539評論 0 6