HotSpot DeMYSTiFieD 之 內存中的對象

大將生來膽氣豪 腰橫秋水雁翎刀

風吹鼉鼓山河動 電閃旌旗日月高

天上麒麟原有種 穴中螻蟻豈能逃

太平待詔歸來日 朕與將軍解戰袍

開篇聊閑天。

在使用Java的過程中,一直困擾我的一個問題是,一個對象到底占用多大內存?(Java并沒有sizeof操作符) 但這個問題,結果卻并沒有那么簡單。

Java沒有sizeof也不需要sizeof操作符,所有數據類型的大小都在Java語言規范中定義,和機器平臺不相關。但從Java虛擬機的角度,一個Java中定義的對象,在虛擬機中占用多大內存?這個問題好像只能通過分析虛擬機的實現來找到答案。這就牽扯到另一個問題,我們到底需不需要了解我們所使用工具的實現?

探索知識的任何階段都是存有疑惑的,就像中學和大學都有數學,但學習深入的程度不同,分別有不同方面的疑惑。我們只是基于一些公知的認識,使其作為本階段學習的起點,并以此展開上層的研究。

少部分人會有一個無止盡思考的奇怪思維現象。舉例來說,我們都知道地球圍繞太陽做周期性公轉,又知道電子圍繞原子核做周期性公轉運動,這和地球繞太陽公轉的行為如出一轍,不禁會讓人想,太陽是不是相當于原子核,地球相當于一個電子,我們都生活在一個電子上。而我們的是身體里有那么多原子和電子,我們的身體是否又定義了另一個新的宇宙。無盡的遐想,無盡的疑惑,雖然有些荒誕,但并非完全不合理。但是如果無休止地問下去,雖然會對底層的科學更加清晰,但是對上層的知識結構的構建非常不利,從而我們需要一個公設,例如認為原子是不可再分的,沒有更小的對象了,一切理論研究以此為基礎展開。例如乘法是基于加法的,在計算3*4的結果時,必須不去質疑為什么1+1=2這件事,并認為它是真理。在學習操作系統時,不去思考硬件內部究竟是如何工作的,只假設硬件是一個給定輸入有給定輸出的系統。

這里的Java虛擬機,作為一個運行字節碼的平臺,顯然不能當做一個公設來看待。虛擬機包含三個概念,語言規范,具體實現和運行實例。語言規范描述了虛擬機需要實現什么,而并沒有規定需要如何去實現。復雜的虛擬機(Hotspot/JRockit/J9)和簡單的虛擬機(Kaffe/Jamvm/cacaovm)在實現方面有很大的差異。對一個有不確定實現的工具,沖一杯咖啡,打開音樂,從源代碼的角度分析工具的實現,對上層知識的構建非常有利(事實也證明,Java使用者對虛擬機的了解程度,遠遠不如c/c++使用者對機器平臺的了解程度深)。

以Hotspot為例,在虛擬機的內部,通過instanceOopDesc來表示一個對象(OOP-Klass二分模型在另一個篇中寫),每個對象包含Mark Word和元數據指針作為對象頭,接下來依次是實例數據和padding:

對象在內存中分布

Mark Word: 定義在oopDesc中的_mark成員,儲存對象運行時的記錄信息,如HashCode/GC分代年齡狀態鎖標志/線程持有的鎖/偏向線程ID/偏向時間戳等。_mark成員的數據類型為markOop,占用內存大小與虛擬機word長度一致。在32位虛擬機上為32位,在64位虛擬機上為64位(可以壓縮)。

元數據指針: 定義在oopDesc中的_metadata成員,指向描述類型的Klass對象指針。根據是否壓縮定義為一個union。虛擬機在運行時頻繁使用這個指針定位到位于方法區的信息。

對象頭中的元信息

虛擬機運行時,每創建一個對象,在虛擬機內部就要創建相應有對象頭的對象,因此對象頭的布局對對象內存空間利用率(Instance Data/Header+instanceData+padding)十分重要。但是,在對象生命周期內,虛擬機要記錄很多信息,如hashCode/GC分代年齡/鎖記錄指針/線程ID 等,因此header必須要仔細設計。

設計1: 虛擬機配置選項-XX:UserCompressedOops。其作用是在64位機器上,對_metadata成員使用32位指針存儲。在64位系統上,指針類型為64位,這樣一來,從32位系統遷移到64位系統時,內存利用率就會有所下降。union聯合體中wideKlassOop是指向klassOopDesc指針,而narrowOop是32位無符號整形。

設計2: _mark成員模仿網絡協議報文頭部,把mark word劃分為多個比特區間,并在不同對象狀態下賦予每個bit不同含義。

Hotspot有三種對象成員排列順序: [oops,longs/doubles/ints/shorts/chars/bytes],[longs/doubles, ints, shorts/chars, bytes, oops] 和 [Fields allocation: oops fields in super and sub classes are together]。默認為第二種順序。源碼如下:

根據allocation_style值的不同應用不同的內存排列模型

排列規則如下,每個對象內存地址要是8的倍數,每個成員的內存地址要是自己大小的倍數,例如整形要是4字節的倍數,long要是8字節的倍數。

假設,在Java代碼中,定義如下類:

定義一個直接繼承Object的類

如果虛擬機不改變成員變量排列順序,32位機器,在內存中順序如下:

按Java代碼中定義順序排列

這樣有14字節因為padding被浪費了。如果重新調整排序規則:

虛擬機重排序過后的排列

這樣只有6字節因為padding被浪費。在每個成員都要內存對齊的情況下,先分配大內存的成員會節約內存。

按照這個規則來計算Object對象的直接子類Boolean,header+value+padding=8+1+7=16,竟然需要16字節。

如果類不是直接繼承Object對象,即父類中如果有成員變量的話。舉例如下:

定義有成員函數的父類

一個B的實例在內存中看起來長這樣:

應用默認規則,先排列父類成員再排列子類成員

其他情況的排序不再贅述,可根據代碼自行排列。

了解Boolean類內存利用率很低以后,再說一下HashMap。對于應用層的程序來說,這簡直是神器,只要創建了之后就可以不斷的丟東西進去,添加刪除都是O(1)操作,又快又好。不過引用第一位圖靈獎獲得者Alan Perlis的名言:“Lisp programmers know the value of everything but the cost of nothing.”,目的是想提醒我們做事情不要忘記背后的代價。對于HashMap來說,代價主要是內存的開銷,試想一下,Java沒有HashMap<boolean,boolean>只有HashMap<Boolean,Boolean>。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,923評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,740評論 3 420
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,856評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,175評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,931評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,321評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,383評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,533評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,082評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,891評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,618評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,319評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,732評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,987評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,794評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,076評論 2 375

推薦閱讀更多精彩內容