JVM笔记 -- Java对象模型

简介

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

  • 对象头(instanceOopDesc) 
    • Mark Word,主要存储对象运行时记录信息,如hashcode, GC分代年龄,锁状态标志,线程ID,时间戳等
    • 元数据指针,即指向方法区的instanceKlass实例,虚拟机通过这个指针来确认这个对象是哪个类的实例。
  • 实例数据,即对象真正存储的有效信息,如代码中定义的字段信息等。
  • 对齐填充,并不是必然存在的,仅起到占位符的作用。由于HotSpot VM的自动内存管理系统要求对象的起始地址必须是8字节的整数倍,也就是说对象的大小必须是8字节的整数倍。而对象头部正好是8字节的倍数(1或2倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。

对象的创建过程

  1. 虚拟机遇到一条new指令时,首先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用所代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。
  2. 类加载检查通过后,接下来虚拟机将为新生对象分配内存,对象所需内存大小在类加载后便可以完全确定。分配的方式有指针碰撞(Bump the Pointer)空闲列表(Free List)两种,具体使用哪种,取决于所采用的垃圾收集器是否带有压缩整理功能决定(GC后的Java堆是否规整),通常使用空闲列表。
  3. 内存分配完后,需要对分配的内存空间进行初始化。这一步骤保证了对象的实例字段在Java代码中可以不赋初始值就可以直接使用。
  4. 执行方法,把对象按照程序员的意愿进行初始化。

指针碰撞:假设Java堆中内存是绝对规整的,所有用过的内存都放到一边,空闲的内存放到另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离。

空闲列表:对于堆中内存分配不规整的情况,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录。

分配内存时的线程冲突问题

对象创建在虚拟机中是非常频繁的行为,即使是仅仅修改一个指针所指向的位置,在并发的情况下也并不是线程安全的,可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针分配内存,造成堆上内存分配冲突的情况。

解决这个问题的方案有两种:

  • 一种是对分配内存空间的动作进行同步处理——实际上虚拟机采用CAS配上失败重试的方法保证更新操作的原子性
  • 另一种则是TLAB(Thread Local Allocation Buffer 本地线程分配缓冲),即每个线程在Java堆中预先分配一小块内存,哪个线程要分配内存,就在哪个线程的TLAB上分配,只有TLAB用完并分配新的TLAB时,才需要同步锁定。

虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来开启,默认是开启的。TLAB空间的内存非常小,缺省情况下仅占有整个Eden空间的1%,当然可以通过选项-XX:TLABWasteTargetPercent设置TLAB空间所占用Eden空间的百分比大小。

oop-klass Model

在JVM中,java对象是通过oop-klass模型体现的。

oop(Ordinary Object Pointer): 普通对象指针,Java程序运行过程中new对象时创建。

klass:  Java类在HotSpot中的c++对等体,用来描述Java类。在jvm加载class文件时,在方法区创建instanceKlass, 表示其元数据,包含常量池、字段、方法等。

  • 实现语言层面的Java类
  • 实现Java对象分发功能

方法区用于存储虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。 所谓加载的类信息,其实不就是给每一个被加载的类都创建了一个 instantKlass对象么。

所以对于一个Java对象的存储可以说:对象的实例(instantOopDesc)保存在堆上,对象的元数据(instantKlass)保存在方法区,对象的引用保存在栈上。

图示

在JVM中,对象在内存中的基本存在形式就是oop。那么,对象所属的类,在JVM中也是一种对象,因此它们实际上也会被组织成一种oop,即klassOop。同样的,对于klassOop,也有对应的一个klass来描述,它就是klassKlass,也是klass的一个子类。klassKlass作为oop的klass链的端点。关于对象和数组的klass链大致如下图:

JVM笔记 -- Java对象模型_第1张图片

在这种设计下,JVM对内存的分配和回收,都可以采用统一的方式来管理。oop-klass-klassKlass关系如图

JVM笔记 -- Java对象模型_第2张图片

 

Mark Word

下图描述了32位虚拟机上,在对象不同状态时 mark word各个比特位区间的含义

JVM笔记 -- Java对象模型_第3张图片

 

参考:

深入理解多线程(二)—— Java的对象模型

深入理解多线程(三)—— Java的对象头

深入理解Java虚拟机

 

 

 

你可能感兴趣的:(jvm)