• JVM 中 java 对象布局


    HostSpot 虚拟机对象布局

    1.java 对象布局

    Java对象分为:对象头、实例数据、对齐填充组合。

    对齐填充:

    对齐填充并不是必然存在的,也没有特定的含义,仅仅起着占位符的作用。由于HotSpot虚拟机的自动内存管理系统要求对象的起始地址必须是8字节的整数倍,也就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或者2倍),因此,当对象实例数据部分没有对齐的时候,就需要通过对齐填充来补全。对象字节数/8的倍数,如果不足的话 实现填充。例如:一个对象21个字节,则需要补充3个字节。

    实例数据:对象中定义的成员属性。

    对象头:

    固定的大小。32位系统对象头大小为8个字节、64位系统对象头大小为16个字节。

    HotSpot虚拟机的对象头(Object Header)包括两部分信息:

    第一部分"Mark Word":用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等.

    第二部分"Klass Pointer":对象指向它的类的元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。(数组,对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是从数组的元数据中无法确定数组的大小。 )

    注意:在64位的虚拟机情况下 mark word 占用64位 ,32位虚拟机占32位。

    64位等于多少 /8 8个字节

    虚拟机源码中查看Mark Word:

     KClass Pointer:

    这一部分用于存储对象的类型指针,该指针指向它的类元数据,jvm通过这个指针确定对象是哪个类的实例。该指针的位长度为JVM的一个字大小,即32位的JVM为32位,64位的JVM为64位。

    如果应用的对象过多,使用64位的指针将浪费大量内存,统计而言,64的JVM将会比32位的JVM多耗费50的内存。为了节约内存可以使用选项 -XX:+UseCompressedOops 开启指针压缩。其中 oop即ordinary object pointer 普通对象指针。

    如果在64位操作系统下,如果对象头字节为12个字节,说明是java虚拟机对对象头进行了压缩。

    对象头压缩设置:

    -XX:+UseCompressedOops 开启指针压缩

    -XX:-UseCompressedOops  不开启指针压缩

    对象头:Mark Word+Klass Pointer类型指针 未开启压缩的情况下

    32位 Mark Word =4bytes ,类型指针 4bytes ,对象头=8bytes =64bits

    64位 Mark Word =8bytes ,类型指针 8bytes ,对象头=16bytes=128bits;

    注意:默认情况下,开启了指针压缩 可能只有12字节。

    new出一个对象对象头占多少个字节:

    如果是32位操作系统对象头占8个字节,如果是64位操作系统对象头占16个字节(没有被压缩的情况下)。

    占用字节=对象头+实例数据+对齐填充/8

     

     

    java 打印对象头信息所需Maven依赖:

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

     

    java 代码实现:对象为 int 类型

    public class UserEntity {
    
        private int a;
    
        public static void main(String[] args) {
            UserEntity userEntity = new UserEntity();
            // 打印对象头信息
            System.out.println(ClassLayout.parseInstance(userEntity).toPrintable());
        }
    }
    
    控制台打印结果:
    com.example.test.UserEntity 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)                           80 30 d1 1b (10000000 00110000 11010001 00011011) (466694272)
         12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
         16     4    int UserEntity.a                              0
         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 代码实现:对象为 Interger 类型

    public class UserEntity {
    
        private Integer a;
    
        public static void main(String[] args) {
            UserEntity userEntity = new UserEntity();
            // 打印对象头信息
            System.out.println(ClassLayout.parseInstance(userEntity).toPrintable());
        }
    }
    
    控制台打印结果:
    com.example.test.UserEntity 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)                           80 30 1c 1c (10000000 00110000 00011100 00011100) (471609472)
         12     4                     (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
         16     8   java.lang.Integer UserEntity.a                              null
    Instance size: 24 bytes
    Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

     Integer包装类型会对int类型自动的进行填充,由4变成了8,能够被8整除。

     

     打印 对象hashcode位置:

    public class UserEntity {
    
        private int a;
    
        public static void main(String[] args) {
            UserEntity userEntity = new UserEntity();
            // 打印 hashCode 所在位置
            System.out.println(Integer.toHexString(userEntity.hashCode()));
            // 打印对象头信息
            System.out.println(ClassLayout.parseInstance(userEntity).toPrintable());
        }
    }
    
    控制台输出:
    5b2133b1
    com.example.test.UserEntity object internals:
     OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
          0     4        (object header)                           01 b1 33 21 (00000001 10110001 00110011 00100001) (557035777)
          4     4        (object header)                           5b 00 00 00 (01011011 00000000 00000000 00000000) (91)
          8     4        (object header)                           00 31 4f 1c (00000000 00110001 01001111 00011100) (474951936)
         12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
         16     4    int UserEntity.a                              0
         20     4        (loss due to the next object alignment)
    Instance size: 24 bytes
    Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
    

    基本数据类型占多少字节

    1、bit --位:位是计算机中存储数据的最小单位,指二进制数中的一个位数,其值为“0”或“1”。

    2、byte --字节:字节是计算机存储容量的基本单位,一个字节由8位二进制数组成。在计算机内部,一个字节可以表示一个数据,也可以表示一个英文字母,两个字节可以表示一个汉字。

    64位/8
    1Byte=8bit  (1B=8bit) 
    1KB=1024Byte(字节)=8*1024bit
    1MB=1024KB
    1GB=1024MB
    1TB=1024GB
    int        32bit  4  
    short    16bit  2
    long      64bit 8
    byte      8bit
    char      16bit
    float      32bit
    double   64bit
    boolean 1bit
    

      

  • 相关阅读:
    OCP-1Z0-051-V9.02-26题
    谨慎使用A2W等字符转换宏
    MySQL 递归查询 当前节点及子节点
    std count_if用法
    OCP-1Z0-053-V12.02-660题
    OCP-1Z0-053-V12.02-667题
    OCP-1Z0-053-V12.02-676题
    OCP-1Z0-051-V9.02-159题
    手工不完全恢复(非归档模式下,日志被覆盖)
    手工完全恢复(非归档模式下,日志没有被覆盖)
  • 原文地址:https://www.cnblogs.com/ming-blogs/p/14481487.html
Copyright © 2020-2023  润新知