专栏首页爱撸猫的杰HotSpot虚拟机对象相关内容

HotSpot虚拟机对象相关内容

一.对象的创建

1.类加载检查

    普通对象的创建过程:虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那么必须先执行相应的类加载过程。

2.分配内存

    分配内存时主要注意两个问题:1.如何分配空间。2.修改指针时如何实现线程安全。

    如果内存是规整的,就使用“指针碰撞”的方式,即将空闲部分的指针移动对象内存大小相等的距离。如果内存不是规整的,虚拟机必须维护一个表,记录那些内存块可用,然后从中选择足够的空间分给要申请的对象实例,这种方式叫“空闲列表”。内存规整指的是一个分界指针恰好分割了已占用内存和空闲内存。

    如何保证修改指针时线程安全。一种方法是对分配内存的空间动作进行同步处理(采用CAS配上失败重试的方式保证跟新操作的原子性);另一种方法是把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存,叫本地线程分配缓冲(Thread Local Allocation Buffer,TLAB),哪个线程需要分配内存,就在那个线程的TLAB上分配,只有TLAB用完并分配新的TLAB时,才需要同步锁定。

3.初始化和设置

    内存分配完成后,虚拟机将分配到的内存初始化为零值(除对象头外),如果使用TLAB分配,也可提前值TLAB分配时进行。

    然后执行<init>方法,把对象按照程序员的意愿进行初始化,这样有个真正可用的对象才算完全产生出来。

二.对象的内存布局

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

1.对象头

    HotSpot虚拟机对象头包括两部分信息:第一部分用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。其数据并不固定,会根据不同状态变化。

    第二部分存储的是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象属于哪个类的实例。如果是数组,还会存储数组长度。

2.实例数据

    这部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都需要记录起来。这部分的存储顺序会受到虚拟机分配策略参数和字段在Java源码中定义顺序的影响。相同宽度的字段总是被分配到一起,在此条件下父类定义的变量会出现在子类之前,如果CompactFileds参数值为true,那么子类中较窄的变量也可能插入到父类变量的空隙之中。

3.对齐填充

    HotSpot以8字节对齐,不满8字节倍数,就需要通过对齐填充来补全。

三.对象的访问定位

    我们需要栈上的reference对象来操纵堆上的具体对象。reference类型在虚拟机中只规定了一个指向对象的引用,并没有定义这个引用应该通过何种方式去定位、访问堆中的对象的具体位置。目前有两种方式。

1.使用句柄

    如果使用句柄的话,在java堆中将划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体的地址信息。如下图示。

2.直接指针

    使用直接指针访问,那么Java堆对象的不居中就必须考虑如何放置访问类型数据的相关信息,而reference中存储的直接就是对象地址。如下图所示。

    这两种对象访问方式各有优势,使用句柄来访问的最大好处就是reference中存储的是稳定的句柄地址,在对象呗移动时只会改变句柄中的实例数据指针,而reference本身不需要修改。

    使用直接指针访问方式的最大好处就是速度更快,它节省了一次指针定位的时间开销,由于对象的访问在Java中非常频繁,因此这类开销积少成多后也是一项非常可观的执行成本。HotSpot使用的第二种方式进行对象访问。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java 各种锁的小结

    从 JDK 1.6 开始,synchronized 做了很多优化,如偏向锁、轻量级锁、自旋锁、适应性自旋锁、锁消除、锁粗化等技术来减少锁操作的开销。

    fengzhizi715
  • 聊聊flink的ParameterTool

    flink-core-1.7.1-sources.jar!/org/apache/flink/api/common/ExecutionConfig.java

    codecraft
  • Kotlin甩掉findViewbyId,原理几何

    在Kotlin中,一个非常好用的特性是:可以直接使用控件 ID 对控件进行操作,而不需要像 Java 中那样先声明控件,使用 findViewById() 来找...

    蜻蜓队长
  • 一文读懂 JAVA 异常处理

    Throwable 是所有异常类型的基类,Throwable 下一层分为两个分支,Error 和 Exception.

    java架构师
  • Java 类的上下转型

    用户2965768
  • springboot原理—一步步分析springboot启动机制(starter机制)

    使用过springboot的同学应该已经知道,springboot通过默认配置了很多框架的使用方式帮我们大大简化了项目初始搭建以及开发过程。本文的目的就是一步步...

    java架构师
  • Java instanceof关键字

    boolean result = child instanceof Parents;

    用户2965768
  • JVM 调优(学习篇)

    公司的江南白衣写了一篇关键业务系统的JVM参数推荐(2016热冬版)的文章,大牛的文章总是需要细细品读。这篇文章介绍大量的JVM调优参数,内容也比较多,本文只是...

    Java团长
  • 使用Spring Boot进行参数校验

    在Spring Boot的官网中,关于Validation只是简单的提了一句,如下

    用户1093975
  • Go并发编程之美-CAS操作

    go语言类似Java JUC包也提供了一些列用于多线程之间进行同步的措施,比如低级的同步措施有 锁、CAS、原子变量操作类。相比Java来说go提供了独特的基于...

    加多

扫码关注云+社区

领取腾讯云代金券