JAVA 對象頭分析

使用JOL來分析java的對象佈局

JOL簡介

JOL的全稱是Java Object Layout。是一個用來分析JVM中Object佈局的小工具。包括Object在內存中的佔用情況,實例對象的引用情況等等。

JOL可以在代碼中使用,也可以獨立的以命令行中運行。命令行的我這裏就不具體介紹了,今天主要講解怎麼在代碼中使用JOL。

使用JOL需要添加maven依賴:

      <dependency>
        <groupId>org.openjdk.jol</groupId>
        <artifactId>jol-core</artifactId>
        <version>0.14</version>
      </dependency>

查看分析vm信息

查看jdk版本

λ java -version
java version "1.8.0_271"
Java(TM) SE Runtime Environment (build 1.8.0_271-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.271-b09, mixed mode)

通過JOL查看jvm信息

public class ObjectHeadTest {
	public static void main(String[] args) {
		//查看字節序
		System.out.println(ByteOrder.nativeOrder());
		//打印當前jvm信息
		System.out.println("======================================");
		System.out.println(VM.current().details());
	}
}

輸出:

LITTLE_ENDIAN
======================================
# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# Objects are 8 bytes aligned.
# Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

上面的輸出中,我們可以看到:Objects are 8 bytes aligned,這意味着所有的對象分配的字節都是8的整數倍。

查看分析基本類型對象佈局

分析String類型

System.out.println(ClassLayout.parseClass(String.class).toPrintable());

輸出:

java.lang.String object internals:
 OFFSET  SIZE     TYPE DESCRIPTION                               VALUE
      0    12          (object header)                           N/A
     12     4   char[] String.value                              N/A
     16     4      int String.hash                               N/A
     20     4          (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

先解釋下各個字段的含義

  • OFFSET是偏移量,也就是到這個字段位置所佔用的byte數,
  • SIZE是後面類型的大小,
  • TYPE是Class中定義的類型,
  • DESCRIPTION是類型的描述,
  • VALUE是TYPE在內存中的值。

分析上面的輸出,我們可以得出,String類中佔用空間的有5部分,第一部分是對象頭,佔12個字節,第二部分是char數組,佔用4個字節,第三部分是int表示的hash值,佔4個字節 ,總共20個字節。但是JVM中對象內存的分配必須是8字節的整數倍,所以要補全4字節,最後String類的總大小是24字節。

分析Long類型

System.out.println(ClassLayout.parseClass(Long.class).toPrintable());

輸出:

java.lang.Long object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0    12        (object header)                           N/A
     12     4        (alignment/padding gap)                  
     16     8   long Long.value                                N/A
Instance size: 24 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total

可以看到1個Long對象是佔24個字節的,但是其中真正存儲long的value只佔8個字節。

分析Long實例對象

System.out.println(ClassLayout.parseInstance(Long.MAX_VALUE).toPrintable());

輸出:

java.lang.Long object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           05 23 00 f8 (00000101 00100011 00000000 11111000) (-134208763)
     12     4        (alignment/padding gap)                  
     16     8   long Long.value                                9223372036854775807
Instance size: 24 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total

可以看出,對象實例的佈局跟類型差不多

分析HashMap外部引用

		HashMap hashMap= new HashMap();
		hashMap.put("flydean","www.flydean.com");
		System.out.println(GraphLayout.parseInstance(hashMap).toPrintable());

輸出:

java.util.HashMap@7106e68ed object externals:
          ADDRESS       SIZE TYPE                      PATH                           VALUE
        76bbcc048         48 java.util.HashMap                                        (object)
        76bbcc078         24 java.lang.String          .table[14].key                 (object)
        76bbcc090         32 [C                        .table[14].key.value           [f, l, y, d, e, a, n]
        76bbcc0b0         24 java.lang.String          .table[14].value               (object)
        76bbcc0c8         48 [C                        .table[14].value.value         [w, w, w, ., f, l, y, d, e, a, n, ., c, o, m]
        76bbcc0f8         80 [Ljava.util.HashMap$Node; .table                         [null, null, null, null, null, null, null, null, null, null, null, null, null, null, (object), null]
        76bbcc148         32 java.util.HashMap$Node    .table[14]                     (object)

Addresses are stable after 1 tries.

從結果我們可以看到HashMap本身是佔用48字節的,它裏面又引用了佔用24字節的key和value。

使用JOL可以分析java類和對象,這個對於我們對JVM和java源代碼的理解和實現都是非常有幫助的。

查看自定義類與實例的對象佈局

public class ObjectHeadTest {

	private int intValue = 0;
	public Integer intValue2 = 999;
	private short s1=256;
	private Short s2=new Short("2222");
	private long l1=222222222222222L;
	private Long l2 = new Long(222222222222222L);
	public boolean isT = false;
	public Boolean isT2 = true;
	public byte b1=-128;
	public Byte b2=127;
	public char c1='a';
	public Character c2 = Character.MAX_VALUE;
	private float f1=22.22f;
	private Float f2=new Float("222.222");
	private double d1=22.222d;
	private Double d2 = new Double("2222.2222");
	private BigDecimal bigDecimal = BigDecimal.ONE;
	private String aa = "asdfasdfasdfasdfds";

	public static void main(String[] args) {
		ObjectHeadTest object = new ObjectHeadTest();
		//打印hashcode
		System.out.println(object.hashCode());
		//打印hashcode二進制
		System.out.println(Integer.toBinaryString(object.hashCode()));
		//打印hashcode十六進制
		System.out.println(Integer.toHexString(object.hashCode()));
		//查看字節序
		System.out.println("======================================");
		System.out.println(ClassLayout.parseClass(ObjectHeadTest.class).toPrintable());
		System.out.println("======================================");
		System.out.println(ClassLayout.parseInstance(object).toPrintable());
	}
}

輸出:

396873410
10111101001111100111011000010
17a7cec2
======================================
com.qhong.basic.jol.ObjectHeadTest object internals:
 OFFSET  SIZE                   TYPE DESCRIPTION                               VALUE
      0    12                        (object header)                           N/A
     12     4                    int ObjectHeadTest.intValue                   N/A
     16     8                   long ObjectHeadTest.l1                         N/A
     24     8                 double ObjectHeadTest.d1                         N/A
     32     4                  float ObjectHeadTest.f1                         N/A
     36     2                  short ObjectHeadTest.s1                         N/A
     38     2                   char ObjectHeadTest.c1                         N/A
     40     1                boolean ObjectHeadTest.isT                        N/A
     41     1                   byte ObjectHeadTest.b1                         N/A
     42     2                        (alignment/padding gap)                  
     44     4      java.lang.Integer ObjectHeadTest.intValue2                  N/A
     48     4        java.lang.Short ObjectHeadTest.s2                         N/A
     52     4         java.lang.Long ObjectHeadTest.l2                         N/A
     56     4      java.lang.Boolean ObjectHeadTest.isT2                       N/A
     60     4         java.lang.Byte ObjectHeadTest.b2                         N/A
     64     4    java.lang.Character ObjectHeadTest.c2                         N/A
     68     4        java.lang.Float ObjectHeadTest.f2                         N/A
     72     4       java.lang.Double ObjectHeadTest.d2                         N/A
     76     4   java.math.BigDecimal ObjectHeadTest.bigDecimal                 N/A
     80     4       java.lang.String ObjectHeadTest.aa                         N/A
     84     4                        (loss due to the next object alignment)
Instance size: 88 bytes
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total

======================================
com.qhong.basic.jol.ObjectHeadTest object internals:
 OFFSET  SIZE                   TYPE DESCRIPTION                               VALUE
      0     4                        (object header)                           01 c2 ce a7 (00000001 11000010 11001110 10100111) (-1479622143)
      4     4                        (object header)                           17 00 00 00 (00010111 00000000 00000000 00000000) (23)
      8     4                        (object header)                           05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)
     12     4                    int ObjectHeadTest.intValue                   0
     16     8                   long ObjectHeadTest.l1                         222222222222222
     24     8                 double ObjectHeadTest.d1                         22.222
     32     4                  float ObjectHeadTest.f1                         22.22
     36     2                  short ObjectHeadTest.s1                         256
     38     2                   char ObjectHeadTest.c1                         a
     40     1                boolean ObjectHeadTest.isT                        false
     41     1                   byte ObjectHeadTest.b1                         -128
     42     2                        (alignment/padding gap)                  
     44     4      java.lang.Integer ObjectHeadTest.intValue2                  999
     48     4        java.lang.Short ObjectHeadTest.s2                         2222
     52     4         java.lang.Long ObjectHeadTest.l2                         222222222222222
     56     4      java.lang.Boolean ObjectHeadTest.isT2                       true
     60     4         java.lang.Byte ObjectHeadTest.b2                         127
     64     4    java.lang.Character ObjectHeadTest.c2                         �
     68     4        java.lang.Float ObjectHeadTest.f2                         222.222
     72     4       java.lang.Double ObjectHeadTest.d2                         2222.2222
     76     4   java.math.BigDecimal ObjectHeadTest.bigDecimal                 (object)
     80     4       java.lang.String ObjectHeadTest.aa                         (object)
     84     4                        (loss due to the next object alignment)
Instance size: 88 bytes
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total

參考

Java對象頭詳解

java頭的信息分析與三種鎖性能分析

java對象在內存中的結構(HotSpot虛擬機)

終於我用JOL打破了你對java對象的所有想象 | 程序那些事

JVM源碼分析之Java對象頭實現

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章