深入理解Java虚拟机 2.HotSpot虚拟机详解

深入理解Java虚拟机 1.HotSpot虚拟机详解

HotSpot虚拟机是Sun JDK额OpenJDK中所带的虚拟机,也是目前使用范围最广的Java虚拟机。在第一文中已经详细分析了JVM的内存模型之后,此文将以HotSpot为例,来详细了解Java堆中对象的创建、对象内存分配和布局、以及对象访问的全过程。

1.对象的创建

在Java中,对象的创建通常是指通过new关键字获取的对象。虚拟机在收到new指令时,首先将会去检查这个指令的参数是否能够在常量池中定位到该类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析、初始化。如果没有,首先执行的类加载过程(类加载过程详见第三文)。在类加载过程完成以后,或者类加载检查通过时,接下来续集你将为新建对象分配具体内存(对象所需内存大小在类加载过程完成之后便可确定),即将一块确定大小的内存从Java堆中划分出来,存储对象。

1.1 分配内存规则

为对象分配内存过程中,将根据内存是否绝对规整,有两种不同的分配方式,一种是“指针碰撞”的方式,另一种是“空闲列表”的方式。

指针碰撞:内存为绝对规整,即所有用过的内存放在一边,未使用的内存放在另一边,中间放着一个指针作为分界点的指示器。这种情况下,为对象分配内存时,将中间放置的指针指示器像存放未使用内存的一边移动一段与对象大小相等的距离,这种分配放到即为“指针碰撞”分配方式。

空闲列表:如果Java堆中的内存不是绝对规整,已使用内存和未使用内存相互交错,则就无法通过指针碰撞的方式为对象分配内存。此时虚拟机需要维护一个列表,该列表记录了哪些内存未使用,哪些内存已使用。在为对象分配内存时,找到一块足够大小的内存空间,划分给对象实例,用于存储新创建的对象实例。然后维护更新列表上未使用和已使用的记录状况。这种分配方式即为“空闲列表”的分配方式。

对象内存的分配方式取决于Java堆内存是否完整,而Java堆内存的是否完整又取决于垃圾收集器是否带有压缩整理功能决定。所以,在使用Serial、ParNew、等带Compact过程的收集器时,系统采用的分配内存方式是指针碰撞;而使用CMS这种基于Mark-Sweep算法的是极其时,通常采用空闲列表的方式。有关垃圾收集器的介绍详见四文。

1.2 并发情况下对象创建的线程安全问题

在一个程序的运行过程中,对象的创建、修改过程非常频繁。这样在多线程并发的情况下,就会存在线程安全的问题,如一个线程正在给对象A分配内存,指针还没来得及修改,而另一个线程中,对象B又使用了原来的指针分配内存,势必会导致内存分配出错。在虚拟机中,解决这个问题有两种方案,一种是对分配内存空间的空座进行同步操作--采用CAS自旋锁以及失败重试的方式来保证更新操作的原子性;另一种方式是对每个线程在Java对中预先分配一小块内存,分配内存的动作按照线程划分在不同的空间之中进行。只有当该快内存分配完之后,再为其分配一块新的的内存空间,通过这种方式亦可实现解决线程安全问题。

2.对象内存布局

在HotSpot虚拟机中,对象在内存中的存储的布局分为3块区域:对象头、实例数据、对齐填充

对象头:对象头包括两部分内容,第一部分是用于存储对象自身的运行时数据,如哈希码、GC分代年龄、线程持有的锁等,另一部分类型指针,即对象指向它的类元数据的指针,通过这个指针来确定这个对象是那个类的实例。这个类型指针并不是一定存在,也就是说查找对象的元数据信息不一定要通过对象本身。另外如果对象是数组,对象头中还必须有一块用于记录数组长度的数据。

实例数据:实例数据部分存储的是对象真正的有效数据

对齐填充:对齐填充部分不是必须存在的,没有特别的含义,主要起着占位符的作用。当对象实例数据区域没有对齐时,需要通过对齐填充来补齐。

3. 对象的访问定位

我们都知道,获取一个对象是通过虚拟机栈中存放的具体地址值,该地址值指向堆中存放的具体的对象实例数据来定位的。当时栈中的地址值是通过何种方式定位到堆中的对象的具体地址。具体的定位方式有虚拟机的实现而定,主流的访问方式有两种,一种是句柄的方式,一种是直接指针的方式。

句柄方式:如果使用句柄方式,首先需要在堆中划分出一块内存作为句柄池,栈中reference存储的就是对象的句柄地址,而句柄中又包含了对象实例数据与类型数据各自的指针。然后通过句柄中的对象实例数据的指针定位到对象具体的实例,通过类型数据指针定位到对象具体的类型数据。如下图:

直接指针:栈中reference存储的就是对象的直接地址,通过reference直接定位到对中对象的具体实例。如下图:

对于两种方位方式优缺点分析:

1.使用句柄访问,优势是reference中存储的是稳定的句柄地址,在对象被移动、修改是只会改变局并重的实例数据指针和句柄中的类型数据指针,而对于reference中的句柄定制并不会边。

2.使用直接指针,优势是访问速度快,相比较于句柄方式,少了一次寻址定位的过程,节省了一次指针定位的时间开销。

 

 

 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值