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对象头实现

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