深入了解Java虚拟机

本文深入探讨了Java对象的创建过程,包括从语言层面的new关键字到虚拟机层面的类加载检查、内存分配、初始化以及对象头、实例数据和对齐填充的内存布局。同时,讲解了对象访问定位的两种主要方式——句柄和直接指针,强调了对象访问速度和内存管理效率的平衡。
摘要由CSDN通过智能技术生成

概述

Java 是一门面向对象语言 Java程序运行过程中无时不刻都有对象被创建出来

对象的创建

语言层面

创建对象通常是new关键字

虚拟机层面

1)类加载检查
当Java虚拟机遇到一个字节码new指令是,首先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用
并且检查 这个符号引用代表的类是否已经被加载、解析、初始化过,如果没有,先执行相应的类加载过程

2)分配内存 (创建对象需要考虑的问题 如何划分可用的空间)
当Java虚拟机类加载检查通过后,虚拟机为新生对象分配内存,对象所需的大小 ,在类加载完成后可完全知道
实际上就是从Java堆中拿一块确定大小的内存块
3)内存空间初始化
内存分配完成后,虚拟机必须将分配到的内存空间(不包括头对象)都初始化为零值
使用TLAB的话 这个操作可以提前至TLAB分配前进行
保证对象的实例字段 在Java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型对应的零值
4)Java虚拟机对对象进行必要的设置(这些信息存放在对象头中) 到这从虚拟机的角度上来看 对象已经产生了 但从Java程序的角度上来看发,对象创建才刚刚开始

			这个对象是哪个类的实例
			如何能找到类的元数据信息
			对象的哈希码值
			对象的GC分代年龄等信息

5)Java程序的角度 对象创建才刚刚开始
构造函数 Class文件中的()方法还没有执行 new字节码指令后执行()方法 按照程序员的意愿对对象进行初始化 一个真正的对象创建完成

对象的内存布局

概述

HotSpot虚拟机里 对象在堆内存中的布局可以划分为三个部分
对象头(Header)
实例数据(Instance Data)
对齐填充(Padding)

对象头

HotSpot虚拟机对象的对象头包括两类信息:
1)第一类 用于存储对象自身的运行时数据(Mark Word)
如 哈希码 GC分代年龄、锁状态标志 线程持有的锁、偏向线程ID、偏向时间戳等、

2)第二类 类型指针 对象指向它的类型元数据的指针
Java虚拟机通过这个指针来确定对象是哪个类的实例,并不是所有的虚拟机实现都必须在对象数据上保留类型指针

对象是Java数组 对象头中还有一块用于记录数组长度的数据,虚拟机通过Java对象的元数据信息确定Java对象的大小

如果数组的长度是不确定的,无法通过元数据中的信息推出数组的大小

实例数据部分

实例数据部分是对象真正存储的有效信息(程序代码里定义的各种类型的字段内容,无论是父类继承下来的还是子类中定义的字段)

对齐填充

对齐填充:这并不是必然存在的,也没有特殊的含义 它仅仅起着占位符的作用

HotStop虚拟机的自动内存管理系统要求对象的起始地址必须是8字节的整数倍 换句话说 任何对象的大小必须都是8字节的整数倍 对象头被设计的正好是8字节的倍数(1倍或2倍)对象实例数据部分没有对齐的话,就需要对齐填充来补齐

对象的访问定位

1、创建对象为了使用对象,Java程序通过栈上的reference数据来操作堆上的具体对象
2、reference类型 在Java虚拟机规范中规定它是一个指向对象的引用,并没有具体定义如何去定位 访问堆中的对象,对象的访问方式也是由虚拟机实现而定
3、主流的访问方式有使用句柄和直接指针(HotStop)两种
4、句柄访问的话,Java堆中可能划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,句柄中包含了对象实例数据,与类型数据的地址信息
1)好处: reference中存储的是稳定句柄地址 在对象被移动(垃圾收集)时只会改变句柄中的实例数据指针,而referencd本身不会被修改
5、指针访问的话, reference中存储的直接就是对象地址
1)好处:访问速度块 ,节省了一次指针定位的开销

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值