Java对象

作者: 老荀 | 来源:发表于2020-04-10 16:40 被阅读0次

本实验平台主要是基于本人的MacbookPro,之后会考虑测试其他操作系统版本
基于jdk1.8,HotSpot
macOS Catalina 10.15
内存 8 GB 2133 MHz LPDDR3

$ uname -a
Darwin MacBook-Pro.local 19.0.0 Darwin Kernel Version 19.0.0: Wed Sep 25 20:18:50 PDT 2019; root:xnu-6153.11.26~2/RELEASE_X86_64 x86_64
$ java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)

jol

在查看Mark Word之前,需要介绍一个openjdk的工具jol

<!-- maven -->
<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.10</version>
</dependency>
// gradle
compile group: 'org.openjdk.jol', name: 'jol-core', version: '0.10'

hello world

System.out.println(ClassLayout.parseInstance(objectDemo).toPrintable());

就可以得到类似下面的输出,默认是把指针压缩给打开的

 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int ObjectDemo.age                            15
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

如果关闭了指针压缩-XX:-UseCompressedOops,结果上多了8个字节

 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           70 c7 8b 08 (01110000 11000111 10001011 00001000) (143378288)
     12     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
     16     4    int ObjectDemo.age                            15
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

对象头

网上说java对象头是分成3个部分的

  • Mark Word
  • 类指针
  • 数组长度(数组才有)
    所以来看下数组对象的对象头
ObjectDemo[] array = new ObjectDemo[12];
System.out.println(ClassLayout.parseInstance(array).toPrintable());

所以从OFFSET16开始记录的是数组的长度12

 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)                           00 bb 68 10 (00000000 10111011 01101000 00010000) (275299072)
     12     4                      (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
     16     4                      (object header)                           0c 00 00 00 (00001100 00000000 00000000 00000000) (12)
     20     4                      (alignment/padding gap)                  
     24    96   jvmtest.ObjectDemo ObjectDemo;.<elements>                    N/A
Instance size: 120 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total

小端序和大端序

CPU的字节序是有两种小端序和大端序,在java中查看也很简单,看到java中是小端序,小端序字节之间是从后往前读的

System.out.println(ByteOrder.nativeOrder());
// LITTLE_ENDIAN

MarkWord

由于我用的是64位的jvm虚拟机,所以MarkWord占64位,而MarkWord按照不同的类型分布是这样的

锁状态 25bit 31bit 1bit 4bit 1bit 2bit
无锁 - hashCode - 分代年龄 0 01
锁状态 54bit 2bit 1bit 4bit 1bit 2bit
偏向锁 threadID epoch - 分代年龄 1 01
锁状态 62bit 2bit
轻量级锁 指向栈中锁记录的指针 00
锁状态 62bit 2bit
重量级锁 指向重量级锁的指针 10
锁状态 62bit 2bit
GC标记 - 11

实战

无锁

而之前的jol打印出来的前两行就是Mark Word

# 无锁
# 标记上索引方便查看
00000001 10010011 00111011 11100101
   0        1         2       3
01100000 00000000 00000000 00000000
   4        5         6       7

由于是小端序需要倒过来看

00000000 00000000 00000000 01100000 11100101 00111011 10010011 00000001
   7         6       5         4        3        2        1       0
# 按照字段来分割的话
00000000000000000000000 001100000111001010011101110010011 0 0000 0 01

偏向锁(无锁)

# 偏向锁(无锁)
00000101 00000000 00000000 00000000
   0        1         2       3
00000000 00000000 00000000 00000000
   4        5         6       7
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000101
   7         6       5         4        3        2        1       0
# 按照字段来分割的话
000000000000000000000000000000000000000000000000000000 00 0 0000 1 01

偏向锁(有锁)

# 偏向锁(有锁)
00000101 01101000 10010000 11011100
   0        1         2       3
10000010 01111111 00000000 00000000
   4        5         6       7
00000000 00000000 01111111 10000010 11011100 10010000 01101000 00000101
   7         6       5         4        3        2        1       0
# 按照字段来分割的话
000000000000000001111111100000101101110010010000011010 00 0 0000 1 01

轻量级锁

# 轻量级锁
10011000 01011001 11110000 00000010
   0        1         2       3
00000000 01110000 00000000 00000000
   4        5         6       7
00000000 00000000 01110000 00000000 00000010 11110000 01011001 10011000
   7         6       5         4        3        2        1       0
# 按照字段来分割的话
00000000000000000111000000000000000000101111000001011001100110 00

重量级锁

# 重量级锁
10001010 00011110 10000001 00101011
   0        1         2       3
11100100 01111111 00000000 00000000
   4        5         6       7
00000000 00000000 01111111 11100100 00101011 10000001 00011110 10001010
   7         6       5         4        3        2        1       0
# 按照字段来分割的话
00000000000000000111111111100100001010111000000100011110100010 10

实例数据&填充PADDING

假设我有一个这样的对象

public class ObjectDemo {
    private int a;
    private short b;
    private short ss;
    private byte c;
    private long d;
    private double e;
    private String s;
    private Integer i;
    private Double g;
    private int[] iarray;
    private Object object;
}

那他的jol输出是

# 对象头部分就忽略了
OFFSET  SIZE                 TYPE DESCRIPTION                               VALUE
     ...
     16     8                 long ObjectDemo.d                              0
     24     8               double ObjectDemo.e                              0.0
     32     4                  int ObjectDemo.a                              0
     36     2                short ObjectDemo.b                              0
     38     2                short ObjectDemo.ss                             0
     40     1                 byte ObjectDemo.c                              0
     41     7                      (alignment/padding gap)                  
     48     8     java.lang.String ObjectDemo.s                              null
     56     8    java.lang.Integer ObjectDemo.i                              null
     64     8     java.lang.Double ObjectDemo.g                              null
     72     8                int[] ObjectDemo.iarray                         null
     80     8   java.lang.Object ObjectDemo.object                           null

由于jvm规定每个java对象的大小都得是8的倍数,所以有7个字节的padding (alignment/padding gap)
也看到包装类都是8个字节长度的,并且默认值也是正确的
而且可以看到对象中的基本类型数据似乎会按照类型进行排列,并非按照书写的顺序

如果我给了初始化值呢

public class ObjectDemo {
    private int a = 7;
    private short b = 8;
    private short ss = 1;
    private byte c = 0;
    private long d = 73473473473L;
    private double e = 3344.23452423423D;
    private String s = "xjj";
    private Integer i = -77;
    private Double g = -1232.34345D;
    private int[] iarray = new int[3];
    private Object object = new Object();
}
 OFFSET  SIZE                TYPE DESCRIPTION                               VALUE
     ...
     16     8                long ObjectDemo.d                              73473473473
     24     8              double ObjectDemo.e                              3344.23452423423
     32     4                 int ObjectDemo.a                              7
     36     2               short ObjectDemo.b                              8
     38     2               short ObjectDemo.ss                             1
     40     1                byte ObjectDemo.c                              0
     41     7                     (alignment/padding gap)                  
     48     8    java.lang.String ObjectDemo.s                              (object)
     56     8   java.lang.Integer ObjectDemo.i                              -77
     64     8    java.lang.Double ObjectDemo.g                              -1232.34345
     72     8               int[] ObjectDemo.iarray                         [0, 0, 0]
     80     8    java.lang.Object ObjectDemo.object                         (object)

相关文章

网友评论

    本文标题:Java对象

    本文链接:https://www.haomeiwen.com/subject/xohfmhtx.html