1.前言
前面已经学习过JVM的内存结构以及垃圾回收机制,对于JVM已经有了一个整体的认识,这章继续深入了解虚拟机,学习堆内存中创建的对象
2. 目录
目录3.对象的内存布局
对象的内存布局在HotSpot虚拟机中,对象的内存布局分为以下3块区域:
- 对象头(Header)
- 实例数据(Instance Data)
- 对其填充(Padding)
3.1.对象头
对象头记录了对象在运行过程中所需要使用的一些数据
- 哈希码
- GC分代年龄
- 锁状态标志
- 线程持有的锁
- 偏向线程ID
- 偏向时间戳
对象头可能包含类型指针,通过该指针能确定对象属于那个类.如果对象是一个数组,那么对象头还会包括数组长度
3.2.实例数据
实例数据部分就是成员变量的值,其中包括父类成员变量和本类成员变量
3.3.对其填充
用于确保对象的总长度为8字节的整数倍
HotSpot VM的自动内存管理系统要求对象的大小必须8字节的整数倍.而对象头部分正好是8字节的倍数(1倍或2倍),因此,当对象实例数据部分没有对齐,就需要通过对其填充来补全
对其填充并不是必然存在,也没有特别的含义,它仅仅起着占位符的作用
4.对象的创建过程
4.1.类加载检查
虚拟机在解析.class
文件时,若遇到一条new
指令,首先它会去检查常量池中是否有这个类的符号引用,并且检查这个符号引用所代表的类是否已被加载,解析和初始化过.如果没有,那么必须先执行相应的类加载过程
4.2.为新生对象分配内存
对象所需内存的大小在类加载完成后便可完全确定,接下来从堆中划分一块对应大小的内存空间给新的对象.分配堆中内存有两种方式:
- 指针碰撞:如果Java堆中内存绝对规整(说明采用的是
复制算法
或标记整理法
),空闲内存和已使用内存中间放着一个指针作为分界点指示器,那么分配内存时只需要把指针向空闲内存挪动一段与对象大小一样的距离,这种方式称为"指针碰撞"- 空闲列表:如果java堆中的内存并不规整,已使用的内存和空闲内存交错(说明采用的是标记清除算法,有碎片),此时,没法简单进行指针碰撞,VM必须维护一个列表,记录其中哪些内存块空闲可用.分配之时从空闲表中找到一块足够大的内存空间划分给对象实例.这种方式称为"空闲列表"
4.3.初始化
分配完内存后,为对象中的成员变量赋上初始值,设置对象头信息,调用对象的构造函数方法进行初始化
至此,整个对象的创建过程就完成了
5.对象的访问方式
所有对象的存储空间都是在堆中分配的,但是这个对象的引用确实在堆栈中分配的.也就是说在建立一个对象时两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在堆栈中分配的内存只是一个指向堆对象的指针(引用)而已.那么根据引用存放的地址类型的不同,对象有不同的访问方式
5.1.句柄访问方式
堆中需要有一块叫做"句柄池"的内存空间,句柄中包含了对象实例数据与类型数据各自的具体地址信息.引用类型的变量存放的该对象的句柄地址(reference).访问对象时,首先需要通过引用类型的变量找到该对象的句柄,然后根据句柄对象的地址找到对象
句柄方式访问对象5.2.直接指针访问方式
引用类型的变量直接存放对象的地址,从而不需要句柄池,通过引用能够直接访问对象.但对象所在的内存空间需要额外的策略存储对象所需要的类信息的地址
直接指针方式访问对象5.总结
本章详细讲解了HotSpot虚拟机对象的内存布局,创建过程及访问方式,对于JVM的运行机制已经有了较为全面的了解
原文:https://www.choupangxia.com/2019/11/11/hotspot-jvm-object/
网友评论