二、深入理解Java虚拟机-虚拟机对象

1、 虚拟机对象创建流程

(1) 虚拟机收到new指令
(2) 检查参数是否在常量池中能够定位到类的符号引用,并且检查所代表的类是否已经被加载解析初始化
(3) 没有,则执行类加载细节
(4) 在堆中为对象分配内存
(5) 虚拟机对对象进行属性设置:对象为哪个类的实例,如何找到类的元数据信息、哈希值、GC分代年龄等信息,存储在对象的对象头中(Object Header)

2、 对象内存分配方式

(1) 指针碰撞:假设堆中内存绝对规整,那么分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离
(2) 空闲列表:假设堆中内存不是规整的,那么虚拟机必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录
(3) 具体使用哪种分配方式由垃圾收集器是否带有压缩整理功能决定。因此,在使用Serial、ParNew等带Compact过程的收集器时,系统采用的分配算法是指针碰撞,而使用CMS这种基于Mark-Sweep算法的收集器时,通常采用空闲列表。

3、 对象创建并发线程安全问题

(1) 问题:并发场景下,虚拟机正在给A分配内存,指针未修改完成时,对象B使用了原指针进行内存分配
(2) 解1:对分配内存空间进行同步处理,虚拟机采用CAS配上失败重试的方式保证更新操作的原子性
(3) 解2:内存分配的动作按照线程划分在不同空间之中,即每个线程都在Java堆中预先分配一小块内存,称为本地线程分配缓冲。哪个线程要分配内存,就在哪个线程的TLAB上分配,只有TLAB用完并分配新的TLAB时,才需要同步锁定。虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来设定。

4、 HotSpot对象的内存布局

布局分为三块区域:对象头、实例数据、对齐填充
(1) 对象头:对象自身的运行时数据:哈希值,GC年龄,锁状态等
a) 运行时数据:官方称为“Mark Word”,根据虚拟机为32位/64位分别为32bit和64bit。32bit未锁定状态下分配为:HashCode(25)+分代年龄(4)+锁标志(2)+固定位0(1),其他状态(轻量级锁定、重量级锁定、GC标记、可偏向)下为:

b) 类型指针:对象指向它的类元数据的指针,虚拟机即通过指针确定对象为哪个类的实例。
c) 如果为java数组,则还包括一块用于记录数组长度的数据
(2) 实例数据:真正的有效信息,即定义的字段内容。存储顺序收到虚拟机分配策略参数和字段在源码中的定义顺序影响
(3) 对齐填充:非必然存在,占位符。由于内存必须为8字节的整数倍,如果没有对齐则通过对齐填充补全。

5、 对象访问定位

主流的访问方式有两种:使用句柄以及直接指针
(1) 使用句柄:

优点:reference中存储的为句柄地址,对象被移动(垃圾回收)时不改变句柄中的实例数据指针,reference本身不需要修改
(2) 直接指针:

优点:速度更快,节省了一次指针定位时间,HotSpot使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值