Java对象的内存布局详细介绍

作者:每天都要进步一点点 时间:2021-07-28 05:11:38 

在HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

一、对象头

Java对象的对象头由三部分组成:

1)、Mark Word

MarkWord用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC分代年龄、同步锁信息、偏向锁标识等等。Mark Word在32位JVM中的长度是32bit,在64位JVM中长度是64bit。

通常我们都是使用的64位的JVM,Mark Word 在64位 JVM 中内部结构如下图:

Java对象的内存布局详细介绍

2)、类型指针

类型指针指向对象的类元数据,虚拟机通过这个指针确定该对象是哪个类的实例。Java对象的类数据保存在方法区。

3)、数组长度(只有数组对象才有)

如果对象是一个数组,那么对象头还需要有额外的空间用于存储数组的长度。如果对象是数组类型,因为JVM虚拟机可以通过Java对象的元数据信息确定Java对象的大小,但是无法从数组的元数据来确认数组的大小,所以用一块来记录数组长度。

二、实例数据

实例数据部分存放类的属性数据信息,包括父类的属性信息。

通过示例说明每个区域具体存放哪些内容:

class Student {
   private String name;
   public Student(String name) {
       this.name = name;
   }
}
public class Demo {
   public static void main(String[] args) {
       Student studentA = new Student("zhangsan");
       Student studentB = new Student("lisi");
   }
}

JVM结构图如下所示:

Java对象的内存布局详细介绍

三、对齐填充

由于虚拟机要求对象起始地址必须是8字节的整数倍,所以后面有几个字节用于把对象的大小补齐至8字节的整数倍,没有特别的功能,对齐填充不是必须存在的,仅仅是为了字节对齐。

为什么必须是8个字节?

根据“计算机组成原理”,8个字节是计算机读取和存储的最佳实践。

四、使用JOL工具分析对象内存布局

接下来我们使用JOL(Java Object Layout)工具,它是一个用来分析JVM中Object布局的小工具。包括Object在内存中的占用情况,实例对象的引用情况等等。

直接在maven工程中加入对应的依赖:

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

通过JOL查看new Object()的对象布局信息:

public class JOLDemo {
   public static void main(String[] args) {
       Object obj = new Object();
       System.out.println("十进制hashCode = " + obj.hashCode());
       System.out.println("十六进制hashCode = " + Integer.toHexString(obj.hashCode()));
       System.out.println("二进制hashCode = " + Integer.toBinaryString(obj.hashCode()));
       String str = ClassLayout.parseInstance(obj).toPrintable();
       System.out.println(str);
   }
}

运行结果如下:

十进制hashCode = 1956725890
十六进制hashCode = 74a14482
二进制hashCode = 1110100101000010100010010000010
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 82 44 a1 (00000001 10000010 01000100 10100001) (-1589345791)
      4     4        (object header)                           74 00 00 00 (01110100 00000000 00000000 00000000) (116)
      8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

解释下各个字段的含义:

  • OFFSET是偏移量,也就是到这个字段位置所占用的字节数;

  • SIZE是后面类型的大小;

  • TYPE是Class中定义的类型;

  • DESCRIPTION是类型的描述;

  • VALUE是TYPE在内存中的值;

从上图可以看出Object obj = new Object();在内存中占16个字节,注意最后面的(loss due to the next object alignment)其实就是对齐填充的字节数,这里由于Object obj = new Object();没有实例数据,对象头总共占用了12个字节(默认开启了指针压缩-XX:+UseCompressedOops),由于虚拟机要求对象起始地址必须是8字节的整数倍,所以还需要对齐填充4个字节,达到2倍的8bit。

Java对象的内存布局详细介绍

来源:https://weishihuai.blog.csdn.net/article/details/126281978

标签:Java,对象,内存,布局
0
投稿

猜你喜欢

  • Spring Security登录表单配置示例详解

    2023-10-12 09:03:55
  • 第三方包jintellitype实现Java设置全局热键

    2023-09-25 10:33:50
  • Java的Spring框架下的AOP编程模式示例

    2023-11-02 00:52:25
  • java8 stream自定义分组求和并排序的实现

    2022-09-12 04:08:26
  • Java注解与反射原理说明

    2021-06-18 01:56:00
  • C# Aspose.Words 删除word中的图片操作

    2023-07-29 12:01:43
  • Maven依赖作用域和依赖传递的使用

    2022-07-24 19:08:33
  • Java开发中为什么要使用单例模式详解

    2023-12-24 21:56:40
  • C#实现顺序栈和链栈的代码实例

    2021-08-17 02:36:40
  • 解析SpringBoot中使用LoadTimeWeaving技术实现AOP功能

    2023-04-19 00:21:47
  • C#调用WebService的方法介绍

    2022-06-05 01:10:30
  • Android实现轮播图片效果

    2023-07-08 02:20:24
  • Java环境下高德地图Api的使用方式

    2022-06-13 06:43:59
  • Java中为什么start方法不能重复调用而run方法可以?

    2023-11-15 03:04:02
  • SpringBoot自定义注解实现Token校验的方法

    2023-11-13 23:17:52
  • Flutter Widget开发之Focus组件图文详解

    2023-06-21 03:47:41
  • 基于Java实现经典蜘蛛纸牌游戏

    2021-09-06 15:22:57
  • Java编程之双重循环打印图形

    2022-02-01 22:06:37
  • Spring Boot集成教程之异步调用Async

    2023-03-10 03:39:50
  • RxJava+Retrofit实现网络请求封装的方法

    2023-08-13 19:39:13
  • asp之家 软件编程 m.aspxhome.com