java对象的内存布局和对象的访问定位

1 、对象在内存中存储的布局分为三块

  • 对象头

    • 存储对象自身的运行时数据:Mark Word(在32bit和64bit虚拟机上长度分别为32bit和64bit),包含如下信息:

      • 对象hashCode
      • 对象GC分代年龄
      • 锁状态标志(轻量级锁、重量级锁)
      • 线程持有的锁(轻量级锁、重量级锁)
      • 偏向锁相关:偏向锁、自旋锁、轻量级锁以及其他的一些锁优化策略是JDK1.6加入的,这些优化使得Synchronized的性能与ReentrantLock的性能持平,在Synchronized可以满足要求的情况下,优先使用Synchronized,除非是使用一些ReentrantLock独有的功能,例如指定时间等待等。
    • 类型指针:对象指向类元数据的指针(32bit–>32bit,64bit–>64bit(未开启压缩指针),32bit(开启压缩指针))

      • JVM通过这个指针来确定这个对象是哪个类的实例(根据对象确定其Class的指针)
  • 实例数据 : 对象真正存储的有效信息

  • 对齐填充
    • JVM要求对象的大小必须是8的整数倍,若不是,需要补位对齐

2 注意

  • 列表内容 Mark Word具有非固定的数据结构,以便在极小的空间内存储尽量多的信息。
  • 如果对象是一个数组,对象头必须有一块儿用于记录数组长度的数据。JVM可以通过Java对象的元数据确定对象长度,但是对于数组不行。
  • 对于对象头长度而言
    • 32bit虚拟机一定是32bit+32bit,即8字节
    • 64bit虚拟机若没有开启了压缩指针,是64bit+64bit,即16字节,若开启了压缩指针,是64bit+32bit,即12字节(不是8bit的倍数)
    • -XX:+UseCompressedOops:开启压缩指针
    • 在《深入理解Java虚拟机(第二版)》中,说对象头是8字节或16字节,不知道是不是有误,自己的系统不是64bit,没有测试
  • 基本数据类型与对应包装类的选用
    这里写图片描述
    reference类型在32位系统上占用4bytes,在64位系统上栈8bytes
    上面文章引用https://www.cnblogs.com/java-zhao/p/5180613.html在java虚拟机第二版中对象内存布局话语官方解释不够详细自此引用上面文章

对象的访问定位
  对象的访问定位就是讲解对象在 JVM虚拟机运行时内存中是怎么引用的
首先java是面向对象的编程语言建立对象就是为了使用对象。我们的java程序需要通过栈上的reference(引用)数据来操作堆上的具体对象。由于reference类型在java虚拟机规范中只规定了一个执行对象的引用,并没有定义这个引用应该通过何种方式去定位,访问堆中对象的具体位置,所以对象访问方式也是取决于虚拟机实现而定的。目前主流的访问方式有使用句柄和直接指针两种。

  • 通过句柄访问对象
    如果使用句柄访问的话,那么java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与对象类型数据各自的具体地址信息,如下图所示
    这里写图片描述

  • 直接指针访问
    如果使用直接指针访问,那么java堆对象的布局中就必须考虑如何访问类型数据的相关信息,而reference中存储的就直接是对象的地址,如下图所示
    这里写图片描述

  这两种访问方式各有优势,使用句柄访问的最大好处就是reference中存储的是稳定的句柄地址,当对象被移动(垃圾收集时移动对象是非常普遍的)时只会改变句柄中的实例数据指针,而reference本身不需要改变。

  使用直接指针访问的最大好处就是速度更快,它节省了一次指针定位的时间开销,由于对象的访问在java中是非常频繁的,因此这类开销积少成多后也是一项非常可观的执行成本。就虚拟机Hot spot而言,他是使用第二种方式进行对象访问的,但从整个软件开发的范围来看,各种语言和框架使用句柄来访问的情况也十分常见

扫描二维码关注公众号,回复: 1723075 查看本文章

猜你喜欢

转载自blog.csdn.net/m0_37034294/article/details/78933876