HotSpot虚拟机理解

HotSpot虚拟机

一、对象创建

  1. new 指令 class。
  2. 检查class是否被加载。
  3. java堆分配内存。
  4. 对象内存空间初始化,对象头初始化。
  5. java的init方法。

JVM参数说明

-XX:+/-UseTLAB

解决内存分配时线程安全

两种方式

  1. 对分配内存空间的动作进行同步处理——实际上虚拟机采用CAS配上失败重试的方式保证更新操作的原子性。
  2. 把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(Thread
    Local Allocation Buffer
    ,TLAB)。哪个线程要分配内存,就在哪个线程的TLAB上分配,只有TLAB用完并且分配新的TLAB时,才需要同步锁定。虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来设定。

对象头的一些信息

Object header
如何找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。
根据虚拟机当前的运行状态的不同,是否启动偏向锁等。

二、对象的内存布局

  1. 对象头(Header)
  2. 实例数据(Instance Date)
  3. 对齐填充(Padding)

对象头

对象头包含两部分信息

  1. 存储对象自身的运行时数据。
  • 哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。

  • 官方称为“Mark Word”。为了节省内存成本,被设计成一个非固定的数据结构以便在极小的空间存储尽可能多的信息。

  • 举例:对象处于未被锁定的状态下,32bit的Mark
    Word的结构,25bit用于存储对象的哈希码,4bit用于存储对象分代年龄,2bit用于储存锁标志位,1bit固定位0。

    HotSpot虚拟机对象头的Mark Word

存储内容 标识位 状态
对象哈希码、对象分代年龄 01 未锁定
指向锁记录的指针 00 轻量级锁定
指向重量级锁的指针 10 膨胀(重量级锁定)
空,不需要记录信息 11 GC标记
偏向线程ID、偏向时间戳、对象分代年龄 01 可偏向
  1. 类型指针,对象指向它的类元数据的指针。
  • 非所有的虚拟机都又这个指针
  • 数组对象时,还需要保留数组长度的数据。因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是从数组的元数据中却无法确定数组的大小。

实例数据

对象真正存储的有效信息。

  • 储存顺序 收到虚拟机默认的分配策略参数(FieldsAllocationStyle)和字段在Java源码定义顺序影响。

HotSpot虚拟机默认的分配策略为:longs/doubles、ints、shorts/chars、bytes/booleans、opps(Ordinary
Object Pointers)。相同宽度的字段总是被分配到一起。

对齐填充

不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。 由于HotShot
VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或者2倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来不全。

三、对象的访问定位

  1. 使用句柄。reference类型指向一个句柄,句柄保存对象实例数据指针和对象类型数据指针。
  • 优点:对象被移动时(垃圾回收时经常出现)只需要修改句柄不用修改reference。
  • 缺点:访问时开销大,需要两次定位。
  1. 直接指针。reference类型直接指向对象实例数据,对象实例数据中存对象的类型数据指针。
  • 优点:访问开销较小,只需要一次定位。
  • 缺点:对象被移动时,需要修改reference。

总结,在java中对象的访问非常频繁,所以访问开销较小的直接指针会有可观的效率。HotSpot虚拟机使用的直接指针。

参考:《深入理解Java虚拟机》周志明 著。

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 像素格子 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读