JavaSE高级篇:HotSpot虚拟机对象探秘

简介: JavaSE高级篇:HotSpot虚拟机对象探秘

这里我们使用最常用的HotSpot虚拟机和Java堆为例,深入单套HotSpot虚拟机在Java堆中的:对象分配、布局和访问的全过程。

第一章:对象的创建

Java程序在一个一个的线程运行的过程中,无数的对象被创建出来。这里讨论的对象的创建仅仅是通过new的方式创建的对象,不包括数组和Class对象。

一:内存分配前的两个校验

当虚拟机遇到一条new指令的时候,首先会检查这个指令的参数是否能在常量池中定位到一个类的符号引用。检查这个符号对应的类是否已经被加载、解析和初始化过,如果没有的话,先进行类加载的过程。

类加载检查通过之后,JVM为新生对象分配内存。对象所需要在内存大小在类加载完成之后就已经存在了(为对象分配空间是加上等同于把一块确定)

二:分配对象空间

指针碰撞:假设Java堆内存中的是绝对规整的(所有被使用过内存都放到了一边,空闲的内存在一边),中间放着一个指针作为分界点指示器。

空闲列表:Java堆内存不是规整的,已经使用的内存和未使用的内存交织在一起。虚拟机需要维护一个列表,记录那些内存块是可用的,分配的时候找一块足够大的内存区域进行分配,并在表中维护记录。

对象分配划分空间会遇到的问题:

对象创建在虚拟机当中十分频繁,仅仅靠修改指针指向位置在并发情况下并非线程安全。可能出现:对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来进行分配内存。

解决这种问题有两个解决方案:对分配内存空间的操作进行同步处理(虚拟机上采用的CAS配上失败重试的方式保证更新操作的愿意性),另外一种就是内存分配按照线程划分在不同的空间进行,每个线程在堆当中有一块本地分配线程缓冲区TLAB,只有该缓冲区使用完了,分配新的缓冲区时才需要进行同步锁定,虚拟机是否需要使用TLAB可以通过-XX:±/UseTLAP来进行设置。

三:对象初始化

对象内存分配完成之后,虚拟机需要将对象的都初始化为零值(不包括对象头),保证对象的实例字段不可以赋值就可以直接使用。如果虚拟机开启了TLAB这块内从在分配内存的时候顺便就做了。

四:对象对象头的设置

虚拟机对对象的对象头进行必要的设置:这个对象是哪个类的实例,如何找到类的元数据,对象的哈希码(真正调用Object.hashcode()的时候才会进行计算),对象GC分带年龄,

以上从虚拟角度来讲,一个对象已经产生了,但是从Java程序角度来看对象创建才刚刚开始,当前构造方法()方法还没有执行所有的字段都是还是默认的零值。对象所需要的其他的资源和状态也没有按照意图构造好。构造方法执行完毕之后,一个真正有用的对象才算真正的被构造出来。

第二章:对象的内存布局

在HotSpot虚拟机中,对象在内存中存储布局分为三个部分:对象头+实例数据+对齐填充

一:对象头存储信息分类

对象头存储信息有两种:对象自身运行时数据+类型指针

1:对象运行时数据

对象自身运行时数据包括:哈希码,GC分代年龄,锁状态标志,线程持有的锁,偏向线程ID,偏向时间戳。未开启压缩指针的前提下,这部分数据长度在32和64位虚拟机分别是32和64个比特,官方将这部分内容称之为Mark Word

32位虚拟机其中一种存储状态为:25比特存哈希码值,4个比特存分代年龄,2个比特存锁标志位,一个比特固定为0

2:类型指针

对象头另外一部分是类型指针,对象指向他的类型元数据的指针,JVM虚拟机通过这个类型指针找到对象该对象是哪个类的实例。当然,并不是所有Java虚拟机都会对象头上保留乐行指针,换句话说查询查找对象的元数据不一定通过对象的本身

如果对象是个Java数组,对象头上还会有一个区域记录数组长度。虚拟机可以通过对象的元数据信息推断出对象的大小,但是数据的长度是不确定的,无法通过元数据信息推断出数组的大小。

二:实例数据部分

实例数据部分存储的是对象部分真实有效的信息,即我们在程序代码中定义的各种类型的字段内容,无论是父类继承下来的,还是在子类中定义的字段都必须记录下来(注意,这里只提到了字段),字段记录顺序会受到-XX:CompactFields参数和源码中字段定义顺序的影响。

存放顺序:按类型存放,相同宽度放一起,在此基础之上父类变量在子类之前。

三:对齐填充

对象都是8字节的整数倍,对象头部分以满足,实例数据不满足的话,需要对齐填充来补齐。

第三章:对象的访问定位

对象创建完之后就是为了使用对象,JVM会通过栈上的reference数据操作堆上的具体对象。reference类型在《Java虚拟机规范中》只规定是他是一个对象的引用。对象的访问方式也是有具体的虚拟机实现的。主流的有两种:

一:句柄

句柄访问的话,在堆中划分出来一块内存作为句柄池,reference当中存储的是对象句柄池中的地址。句柄池中包含了对象的实例数据和类型数据的地址

二:直接指针

使用直接指针的话,reference存储的就是直接的对象地址,只访问对象本身的话,就不需要多一次间接访问开销。但是这种Java中的堆中对象需要考虑如何放置对象的类型信息(对象头)

三:总结比较

句柄最大好处就是reference当中存储的稳定的句柄地址,对象被移动后(垃圾收集时移动对象很普遍)只会改变句柄中的对象实例的地址,reference本身不会改变。

直接指针的放回寺就是速度快,节省了一次指针定位的时间开销。HotSpot使用的就是这个,当然此虚拟机有额外情况,使用shenandoah收集器的话也会有一次额外的转发。

相关文章
|
存储 缓存 Java
深度解密 Python 虚拟机的执行环境:栈帧对象
深度解密 Python 虚拟机的执行环境:栈帧对象
269 13
|
存储 Python
解密虚拟机的执行环境:栈帧对象
解密虚拟机的执行环境:栈帧对象
120 0
|
算法 Java
Java垃圾回收(Garbage Collection,GC)是Java虚拟机(JVM)的一种自动内存管理机制,用于在运行时自动回收不再使用的对象所占的内存空间
【6月更文挑战第18天】Java的GC自动回收内存,包括标记清除(产生碎片)、复制(效率低)、标记整理(兼顾连续性与效率)和分代收集(区分新生代和老年代,用不同算法优化)等策略。现代JVM通常采用分代收集,以平衡性能和内存利用率。
185 3
|
Linux 虚拟化
部署04-ncpa.cpl 虚拟机介绍,什么是虚拟机,怎样使用虚拟机,安装VMWARE,WorkStation,VMWARE这款软件是收费软件,可以在一个月期间进行使用,成功看VMWARE高级网络设置
部署04-ncpa.cpl 虚拟机介绍,什么是虚拟机,怎样使用虚拟机,安装VMWARE,WorkStation,VMWARE这款软件是收费软件,可以在一个月期间进行使用,成功看VMWARE高级网络设置
|
存储 缓存 安全
深入浅出JVM(三)之HotSpot虚拟机类加载机制
深入浅出JVM(三)之HotSpot虚拟机类加载机制
|
存储 缓存 算法
深入浅出JVM(一)之Hotspot虚拟机中的对象
深入浅出JVM(一)之Hotspot虚拟机中的对象
|
存储 缓存 算法
HotSpot 虚拟机对象存储逻辑
HotSpot 虚拟机对象存储逻辑
150 0
|
Ubuntu Java Unix
《HotSpot实战》—— 1.2 动手编译虚拟机
由于开发环境各不相同,每个人遇到的问题可能都不尽相同;即使遇到相同的问题,在不同的平台上解决的方式可能也有所不同。当然,对于相同的问题,也会有多种办法解决。限于篇幅,在这里不能对所有错误信息和解决办法都列举出来。
5525 1
|
2月前
|
Oracle 关系型数据库 虚拟化
在VMware的Win10虚拟机中安装使用ENSP
本文介绍了在Windows 10虚拟机上安装ENSP及相关软件的全过程,包括VirtualBox、WinPcap、Wireshark、VLC和ENSP的安装步骤,并提供图文演示,帮助用户顺利完成配置与测试。
867 134
|
1月前
|
Linux 虚拟化 iOS开发
VMware Remote Console 13.0.1 for macOS, Linux, Windows - vSphere 虚拟机控制台的桌面客户端
VMware Remote Console 13.0.1 for macOS, Linux, Windows - vSphere 虚拟机控制台的桌面客户端
388 0
VMware Remote Console 13.0.1 for macOS, Linux, Windows - vSphere 虚拟机控制台的桌面客户端