摘要:堆內存用于存放我們在程序中創建的對象,一旦沒有足夠的空間用于存放這些對象,即會拋出異常。當我們采用后一種方式時,我們需要了解一個對象是如何占據堆內存空間的,或者說是了解一個對象是由哪些部分組成的。
JVM將內存劃分為程序計數器(Program Counter Register)、虛擬機棧(VM Stack)、本地方法棧(Native Method Stack)、堆(Heap)以及方法區(Method Area)。作為開發者,我們最關注的是虛擬機棧以及堆這兩塊區域。虛擬機棧所需要的內存空間在編譯期間即可明確,而堆內存所需要的空間需要在運行時才可確定。堆內存用于存放我們在程序中創建的對象,一旦沒有足夠的空間用于存放這些對象,即會拋出OutOfMemoryError異常。在這種情況下,我們可以調整堆內存的大小,或者對程序進行優化。當我們采用后一種方式時,我們需要了解一個對象是如何占據堆內存空間的,或者說是了解一個對象是由哪些部分組成的。
對象的內存布局在HotSpot虛擬機中,對象在內存中的布局劃分為3個區域:對象頭(Header),實例數據(Instance Data)以及對齊填充(Padding)。
對象頭HotSpot虛擬機對象的對象頭一般包含兩部分信息,第一部分用于存儲對象自身的運行時數據,例如HashCode、GC分代年齡等信息。在32位和64位的JVM中,這部分數據分別為32bit和64bit,官方稱這部分數據為Mark Word。
另一部分用于存儲對象的類型指針,該指針指向它的類元數據,JVM通過這個指針確定對象是哪個類的實例。在32位JVM中,指針的長度為32bit,在未開啟壓縮指針的64位JVM中,該指針的長度為64bit,如果開啟壓縮指針,那么為32bit。
之前提到對象頭一般包含兩部分信息,這是因為如果對象是一個數組,那么對象頭還需要有額外的空間用于存儲數組的長度,并且這部分數據也隨著JVM位數的不同而不同:32位的JVM上,該區域的長度為32bit,在64位未開啟壓縮指針的JVM中,這部分數據的長度為64bit,否則為32bit。
實例數據實例數據部分是對象真正存儲有效信息的區域,存儲了代碼中定義的各種字段的內容,包括從父類繼承下來的字段和子類中定義的字段。
實例數據緊隨對象頭,為了提高存儲空間的利用率,這部分數據的存儲順序會受到虛擬機分配策略參數和字段在Java源碼中定義順序的影響。HotSpot虛擬機默認的分配策略如下所示。
doubles & longs
ints & floats
shorts & chars
booleans & bytes
references
可以看出,相同寬度的字段總是被分配到一起,并且在滿足這個條件的前提下,在父類中定義的字段會出現在子類字段之前。
對齊填充對齊填充這部分不是必須存在的,這部分僅僅是起著占位符的作用。由于HotSpot虛擬機的自動內存管理系統要求對象的起始地址必須是8字節的整數倍,因此當對象實例部分數據沒有對齊時,就需要對剩余的部分進行填充。
度量工具從JDK 5開始, Java提供了Instrumentation API,通過getObjectSize方法來獲取對象的大小,但是getObjectSize方法存在如下兩個缺陷,不能準確的計算對象的大小。
不能直接調用getObjectSize方法,而是需要通過-javaagent參數指定一個特定的jar文件(包含Instrumentation代理)來啟動Instrumentation的代理程序。
如果一個對象中包含別的對象的引用,那么getObjectSize方法僅僅計算引用的大小,而不包括引用所指向的對象的大小。
由于上述兩個缺陷,我們不能直接調用getObjectSize方法來計算對象的大小,但是利用Java的反射機制,我們可以完整的計算一個對象的大小。我們解析對象的每一個Field(使用getDeclaredFields),并遵從如下規則。
當Field是基本數據類型時,我們不再計算該Field的大小,因為該Field的大小已經被包含在getObjectSize方法的返回值中。
當Field是靜態數據或者是常量池中包含的數據,那么我們忽略這些數據,因為這些數據并不是屬于對象的。
我們需要保存我們已經計算過的對象的引用,防止重復計算。
如果對象所屬的類存在父類,還需要計算父類中成員變量的大小。
jvm-obj-size 是以上思想的具體實現,jvm-obj-size 實現了基本的獲取對象本身的大小(sizeOf,僅包含引用本身),以及獲取對象真正的大小(fullSizeOf,包含引用所指向的對象)的方法,具體用法以及測試代碼詳見README文件。
參考深入理解Java虛擬機
Again about determining size of Java object
Java SE 6 新特性: Instrumentation 新功能
Java對象大小內幕淺析
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66290.html
摘要:再附一部分架構面試視頻講解本文已被開源項目學習筆記總結移動架構視頻大廠面試真題項目實戰源碼收錄 Java反射(一)Java反射(二)Java反射(三)Java注解Java IO(一)Java IO(二)RandomAccessFileJava NIOJava異常詳解Java抽象類和接口的區別Java深拷貝和淺拷...
摘要:前言本文內容基本摘抄自深入理解虛擬機,以供復習之用,沒有多少參考價值。此區域是唯一一個在虛擬機規范中沒有規定任何情況的區域。堆是所有線程共享的內存區域,在虛擬機啟動時創建。虛擬機上把方法區稱為永久代。 前言 本文內容基本摘抄自《深入理解Java虛擬機》,以供復習之用,沒有多少參考價值。想要更詳細了解請參考原書。 第二章 1.運行時數據區域 showImg(https://segment...
摘要:通過分析源碼,不難發現,主要是通過循環解析文件并將信息解析到內存對象,布局文件中定義的一個個組件都被順序的解析到了內存中并被父子的形式組織起來,這樣通過給定的一個就可以將整個布局文件中定義的組件全部解析。 目錄介紹 01.前沿介紹 02.handleLaunchActivity 03.performLaunchActivity 04.activity.attach 05.Activi...
閱讀 2686·2021-09-22 15:58
閱讀 2230·2019-08-29 16:06
閱讀 898·2019-08-29 14:14
閱讀 2810·2019-08-29 13:48
閱讀 2451·2019-08-28 18:01
閱讀 1495·2019-08-28 17:52
閱讀 3318·2019-08-26 14:05
閱讀 1610·2019-08-26 13:50