HotSpot虚拟机(1)

HotSpot虚拟机(1)

对象的创建

对于Java中一条new的指令,在虚拟机中需要进行如下几步过程才能完成创建对象:

  1. 检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号应用代表的类是否已经被加载、解析和初始化,如果没有,那必须先进性相应的类加载过程

  2. 在类加载检查通过后,接下来虚拟机将为新生对象分配内存(对象所需的内存大小在类加载之后便可确定),而内存的划分分为两种:
    - Java堆中内存是绝对规整的:所有用过的内存都放在一边,空闲的内存放在另一边,中间放一个指针作为分界点的指示器。这种方式通过挪动指针来分配内存,称作“指针碰撞”(Bump the Pointer)
    - Java堆中的内存并不是规整的:即使用过的内存和空闲的内存相互交错,这时再分配新内存的时候需要从列表中找到一块足够大的空间来满足对象实例,并更新列表上的记录,这种分配方式称为“空闲列表”(Free List)

    选择哪种分配方式是由Java堆是否规整决定,其实本质上是由所采用的垃圾收集器是否带有压缩整理功能决定。

    这里注意一点,在并发情况下创建对象的行为在虚拟机中并不是线程安全的(可能会出现正在给A分配内存,指针还没有来的及修改,对象B又同时使用了原来的指针来分配内存的情况),解决这个问题有两种方案:

    • 对分配内存空间的动作进行同步处理,实际上虚拟机是采用CAS配上失败重试的方式保证更新操作的原子性
    • 还可以把内存分配的动作按照线程划分在不同的空间中进行,其实就是给每个线程预分配一块内存,称作本地线程分配缓冲(TLAB),这时哪个线程需要分配内存就从哪个线程的TLAB上分配。一旦预分配的TLAB使用完了并需要分配新的时,才需要同步锁定。
  3. 分配内存完之后,虚拟机需要将分配的内存初始化零值(不包括对象头),这一步骤确保了对象的实例字段在java代码中可以不赋初始值就可以直接使用。

  4. 接下来,虚拟机需要对对象进行必要的设置,这些信息储存在对象的对象头

  5. 这时,从虚拟机的角度来看,一个新的对象已经产生了,但此时方法还没有执行。所以,一般来说,在执行new指令之后会接着执行方法,把对象按照程序员的医院惊醒初始化,这样一个真正可用的对象才算是完全产出。

对象的访问

在Java程序中,我们需要通过栈上的reference数据来操作对上的具体对象。访问方式主要有两种:

  1. 使用句柄访问: 在Java堆中将会划分出一块内存作为句柄池,reference中储存的时对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息。这种方法的优点时reference中储存的是稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而不需要改变reference本身
  2. 使用直接指针访问: java堆对象的布局中需考虑如何放置访问类型数据的相关信息,而reference中储存的直接就是对象地址。这种方法的最大好处就是速度更快,他节省了一次指针定位的时间开销,由于访问对象十分频繁,所以这类开销积少成多后是一项十分可观的成本。

ps:关于对象头和CAS的理解留坑,之后填。

Reference:《深入理解Java虚拟机——JVM高级特性与最佳实践(第2版)》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值