JVM对象原理分析

作为一个java程序员,我们每天都在创建各种对象,但是你有没有思考过,当你 new 一个对象的时候,jvm 做了哪些工作呢?今天就让我们一起来研究下,java对象的底层原理。

对象分配

一个对象的创建可以分为以下几步。

检查加载、分配内存、内存空间初始化、设置、对象初始化

下面我们一一来分析每一个步骤

1) 检查加载

jvm 首先会去加载我们的 class 文件,这个步骤可以从本地加载,也可以从网络中去加载

2) 分配内存

我们首先提出两个问题

  1. jvm是如何确可用的内存空间的
  2. 如果有两个线程同时 new 对象,如何避免分配的内存空间重叠(并发安全问题)

下面我们一一 解释这两个问题

jvm是如何确可用的内存空间的

指针碰撞:
如果堆内存区域规整,所有用过的内存放在一边,没用过的 放在一边,中间有一个指针来指示,那分配内存就是把那个指针向空闲的区域移动一段距离(对象的大小),如下图所示
在这里插入图片描述
空闲列表

如果内存区域不规整,已使用和未使用的区域相互交错,采用空闲列表的方式,虚拟机会维护一个列表,列表上记录了哪些区域使用了,哪些区域未使用.,分配的时候就从列表中找一块足够大的空间给对象,堆中的内存区域是否规整,取决于采用的垃圾收集器是否带有压缩功能。
在这里插入图片描述
发安全问题

CAS 机制
分配内存的时候采用cas机制,保证分配的原子性

分配缓冲(TLAB
每个线程在java堆中,预先分配一块私有的内存地址,线程如果需要分配内存,就在自己的这个私有的这个区域分配
当空间不足的时候,再从eden 区 申请一块继续使用

3) 内存空间初始化

内存分配完毕后,将分配到内存空间都初始化0值。比如 int 就初始化成 0,boolean 就设置成 false 。
注意这里的初始化是jvm的初始化。
这一步保证了 java的对象实例字段,在java代码中可以不赋值,就可以直接使用。

4)设置

虚拟机对对象的头部进行一些必要的设置

如:

这个对象是哪个类的示例

如何才能找到类的元数据信息

对象的gc分代年龄等信息

这些都存放在对象的头部中

5)对象初始化

上面的步骤完成以后,对于jvm虚拟机来说,一个新的对象已经产生了,但是从java程序的角度来说对象的创建才刚刚开始。

这一步就是给对象赋值,并执行构造方法

对象的访问定位

经过上面的分析,我们已经掌握了如何去创建一个对象了。
那么接下去我们要分析的就是,如何去jvm里访问到我们创建的对象

句柄池

jvm中回去维护一个句柄池,句柄池中的对象,存放两个信息,一个是对象实例的地址,一个是对象所对应类的地址
然后,我们的引用直接指向句柄池中的的元素。
这样设计的好处是,对象在jvm中由于 gc,所以地址的变化是十分频繁的,用句柄池就可以将 我们对对象的引用,和对象的实际位置隔离开来,对象位置发生变化的时候,reference不用更改,减少了维护的开销
在这里插入图片描述

直接指针

直接指针去掉了句柄池,直接将reference 指向了我们的对象实例,然后对象的头部又存放着对象的类型。
这样的模式的优点,相对于使用句柄池就减少了一次地址的定位的开销,由于对象的访问很频繁,积少成多,可是很可观的,
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值