標籤:計算java對象大小 對象在記憶體中的儲存 jol工具使用 java物件版面配置
最近在學習java對象記憶體布局方面的一些知識,主要是想知道一個java對象到底佔用多少記憶體空間,以及java對象在記憶體中到底是什麼樣子的。c/c++中的sizeof運算子能夠方便地告訴我們一個變數佔用的記憶體空間,但是在java中卻沒有直接提供這種機制。如果想擷取java對象佔用的記憶體大小,可以利用java的Instrumentation機制。java.lang.instrument.Instrumentation這個介面提供了getObjectSize(Object objectToSize),能夠告訴我們一個對象的大小。如何擷取Instrumentation對象,網上有很多資料,這裡不再贅述。
public static void main(String[] args){// 通過pre-agent擷取Instrumentation對象Instrumentation instr = AgentGetter.getInstrumentation();System.out.println(instr.getObjectSize(new Object()));}
Java對象的記憶體布局:對象頭(Header)、執行個體資料(Instance Data)和對齊填充(Padding)。無論是32位還是64位的HotSpot,使用的都是8位元組對齊。也就是說每個java對象,佔用的位元組數都是8的整數倍。(對象頭 + 執行個體資料 + padding) % 8等於0且0 <= padding < 8。在網上看到各種介紹如何手動計算對象大小的文章,總結了幾點:
1.基礎資料型別 (Elementary Data Type)佔用的位元組數,JVM規範中有明確的規定,無論是在32位還是64位的虛擬機器,佔用的記憶體大小是相同的。
2.reference類型在32位JVM下佔用4個位元組,但是在64位下可能佔用4個位元組或8個位元組,這取決於是否啟用了64位JVM的指標壓縮參數UseCompressedOops。
3.new Object()這個對象在32位JVM上佔8個位元組,在64位JVM上佔16個位元組。
4.開啟(-XX:+UseCompressedOops)指標壓縮,對象頭佔12位元組; 關閉(-XX:-UseCompressedOops)指標壓縮,對象頭佔16位元組。
5.64位JVM上,數組對象的對象頭佔用24個位元組,啟用壓縮之後佔用16個位元組。之所以比普通對象佔用記憶體多是因為需要額外的空間儲存數組的長度。
6.對象記憶體布局中的執行個體資料,不包括類的static欄位的大小,因為static欄位是屬於類的,被該類的所有對象共用。
更具體的可以參考“一個Java對象到底佔用多大記憶體?”這篇文章。在網上搜尋的過程中看到了java object layout這個小工具,能夠列印出類的布局資訊。
項目的首頁是:http://openjdk.java.net/projects/code-tools/jol/,
項目代碼在http://central.maven.org/maven2/org/openjdk/jol/。
下載jol-core-0.3.2.jar之後,將其加入項目的build path,通過下面的代碼就可以查看某個類的布局資訊。
package jol;import org.openjdk.jol.info.ClassLayout;import org.openjdk.jol.util.VMSupport;public class T1 {public static void main(String[] args) throws Exception {System.out.println(VMSupport.vmDetails()); System.out.println(ClassLayout.parseClass(VO.class).toPrintable());}}運行這段代碼,可以看到jol輸出如下資訊:
Running 64-bit HotSpot VM.Objects are 8 bytes aligned.Field sizes by type: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]Array element sizes: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]jol.VO object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 16 (object header) N/A 16 8 long VO.b N/A 24 4 int VO.a N/A 28 4 (loss due to the next object alignment)Instance size: 32 bytes (estimated, the sample instance is not available)Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
可以看到jol工具,能夠顯示出對象頭的大小,以及每個執行個體欄位的位移,進而計算對象佔用的記憶體大小。
jol工具還提供了一個命令列工具jol-cli-0.3.2-full.jar,包含了main方法能夠直接在命令列運行,查看類的布局資訊。可以從這裡下載jol-cli工具。
#查看jdk系統類別的布局資訊>java -jar jol-cli-0.3.2-full.jar internals java.lang.Object
#如果我們自己的jar放在C:\Program Files\Java\jdk1.7.0_80\jre\lib\ext\下,那麼會自動載入;#如果我們自己的jar放在C:\Program Files\Java\jdk1.7.0_80\jre\lib\下,那麼不會自動載入(可能是因為安全問題#,bootstrap類載入器僅僅載入jdk的核心類);>java -jar jol-cli-0.3.2-full.jar internals net.aty.VO
#方式1:指定classpath,查看自己的類布局>java -jar jol-cli-0.3.2-full.jar internals -cp mydemo.jar net.aty.VO
#方式2:指定classpath,查看自己的類布局>java -cp mydemo.jar;jol-cli-0.3.2-full.jar org.openjdk.jol.Main internals net.aty.VO
上面幾種方式都能夠正確運行,但是下面這種方式是錯誤的,會報錯ClassNotFoundException。
#注意:這種方式會報錯:java.lang.ClassNotFoundException:#這是因為:如果採用了-jar參數來運行可執行檔jar包,JVM會忽略你設定的classpath以及所有環境變數java -cp mydemo.jar -jar jol-cli-0.3.2-full.jar internals net.aty.VO
java對象的記憶體布局(一):計算java對象佔用的記憶體空間以及java object layout工具的使用