JVM(八):Java 对象模型

JVM(八):Java 对象模型

本文将学习对象是如何建立的,对象的内存布局,以及如何定位访问一个对象。java

对象建立

当虚拟机碰到一个new指令时,首先检查指令参数可否在常量池中定位一个类的符号引用,而且检查该符号引用对应的类是否已经被加载,解析和初始化。当一切都肯定完成后,JVM就会为其分配内存(须要分配的内存大小在如今就已经肯定,在 下面 中详细讲述)。算法

对象的内存分配方式分为如下两种:jvm

  1. 指针碰撞,这种分配方式创建在堆内已用空间和剩余空间是完整的,这样的话,在二者之间放置一个指针做为分界点的指示器便可,在分配空间时,只须要移到一下指针位置就行了。
  2. 空闲列表,若是 JVM 内的空间不是规整的,那么就只能采用此方案了。此时 JVM 会维护一个列表,记录了哪些内存块是可用的,在分配的时候划一个大小足够的区域给对象实例,并更新列表便可。

以上两种方式采起哪一种,取决于 Java 堆是否工整,而堆是否工整又取决于垃圾回收算法是否具备整理功能。布局

对象模型

前面说到对象在建立时就已经肯定了内存大小,那么 JVM 是怎么肯定对象的大小呢?对象在内存中又是如何存储的呢?学习

在 JVM 中 Java 的对象模型分为如下3块,对象头实例数据对齐填充,下面就让咱们来分别介绍一下。线程

对象头

对象头的数据包括两部分。一部分是用于存储自身运行时数据,这部分数据被官方称为“Mark World”。其中存储数据包括Hashcode、GC 分代年龄、锁状态标志、线程持有锁、偏向线程ID、偏向时间戳等等指针

对象头的另一部分是 类型指针,即对象指向其类元数据的指针。经过这个指针,咱们就能够知道该实例属于哪一个类。code

实例数据

实例数据就是对象真正存储的有效信息,也就是代码中定义的各类类型的字段内容,不管是父类的仍是子类的,都须要记录下来。其存储顺序受到虚拟机分配策略和定义顺序影响。对象

对齐填充

对象填充不是必要数据。在模型中只是起到占位符的做用。由于 HotSpot 要求对象起始地址必须是8的整数倍,这样在实例数据达不到要求的时候,就须要经过对齐填充来补齐。blog

对象访问

对象访问的方式是经过引用来定位、访问。但 JVM 规范并无强制要求该经过何种方式使用引用,所以具体实现仍是要依赖与具体虚拟机类型。

不过目前的主流访问方式就是如下两种。

  1. 使用引用。其在 Java 堆中会独立建立一个句柄池,引用指向句柄,而句柄指向实例数据和类型数据。
    使用句柄访问

使用这种方式来访问的优势是稳定,例如在 GC 后,实例数据须要移动,那么只须要修改句柄池中的内容便可,reference 指向的是稳定的位置,缺点是这种方式须要二次定位,速度较慢。

  1. 直接指针访问,引用直接堆中对象地址,堆中保存了实例数据和类型数据指针,指针直接指向另外存储的类型数据。
    经过直接指针访问对象

使用这种方式的优势是访问实例数据快,由于 reference 指向直接的对象,省去了一次内存定位开销。但缺点就是不够稳定,在对象移动后,reference 也须要修改值。

具体采用何种,不一样的虚拟机有不一样的实现,由于二者各有千秋,并无强烈的优缺点,所以不一样状况不一样处理便可。

总结

在本文中介绍了对象的本质模型是什么,以及对象是如何建立和访问使用的,与上文的 JVM 内存模型结合来看,可让咱们了解内存泄露产生的缘由,有助于高效地理解使用 Java 的自动内存管理机制。

iceWang公众号

文章在公众号“iceWang”第一手更新,有兴趣的朋友能够关注公众号,第一时间看到笔者分享的各项知识点。谢谢!笔芯!

本系列文章主要借鉴自《深刻分析 Java Web 技术内幕》和《深刻理解 Java 虚拟机-JVM 高级特性与最佳实践》。 ​

相关文章
相关标签/搜索