JVM_补充内容
提示: 本材料只做个人学习参考,不作为系统的学习流程,请注意识别!!!
五.对象的实例化、内存布局和访问定位
1. 对象的实例化
创建对象的方式
- new(最常见方式):包括单例模式、构造者模式、工厂模式
- Class 的 newInstance():反射方式,只能调用空参构造器,权限是public
- Constructor的的 newInstance(Xxx):反射方式,可调用空参或带参构造器,权限没有要求
- clone():不调用任何构造器,当前类需要实现Cloneable接口,实现clone()方法(深浅克隆对比?)
- 反序列化:从文件或网络中获取对象的二进制流
- 第三方库Objenesis
创建对象的步骤
- 判断对象对应的类是否加载、链接、初始化:
虚拟机遇到new指令,首先检查该指令的参数是否在元空间的常量池中定位到一个类的符号引用,并检查这个符号引用所代表的类是否被加载、解析和初始化。(判断类元信息是否存在),如果没有则通过双亲委派机制去加载.class文件。- 为对象分配内存
计算对象占用空间的大小,接着在堆划分一块内存给新对象
①内存规整,使用指针碰撞:即所有用过的内存在一边,空闲的内存在另一边,中间放着一个指针作为分界点的指示器,分配内存仅仅就是把指针向空闲的那边移动一段与对象大小相等的距离。如果使用Serial、ParNew这种基于压缩算法的垃圾收集器,虚拟机就会使用这种分配方式,一般带有整理过程的收集器使用指针碰撞。
②内存不规整,虚拟机维护一个列表,使用空闲列表分配:虚拟机维护一个列表,记录哪些内存块是可用的,在分配的时候从列表找到一块足够大的空间划分给实例对象,并更新列表上的内容。
注: 选择哪种分配方式是由Java堆是否规整决定,而Java堆是否规整是由所采用的的垃圾收集器是否带有压缩整理功能决定的。- 处理并发问题
①CAS(Compare And Swap)失败重试、区域加锁,保证指针更新操作的原子性(锁相关知识?)。
②TLAB:把内存分配的动作按照线程划分在不同的空间中进行。- 初始化分配到的空间(属性的默认初始化:对应下面说明的步骤①)
内存分配结束,虚拟机将分配到的内存空间都初始化为零值(不包括对象头)。保证对象的实例字段在Java代码中可以不用赋值就可以直接使用,程序能访问到这些字段的数据类型对应的零值。- 设置对象的对象头
将对象的所属类(类的元数据信息)、对象的HashCode和对象的GC信息、锁信息等数据存储在对象的对象头中,这个过程的具体设置方式取决于JVM实现。- 执行< init >方法进行初始化(对应下面说明的步骤①②③)
从Java程序的视角看来,初始化才正式开始。初始化成员变量,执行实例化代码块,调用类的构造方法,并把堆内对象的首地址赋值给引用变量。说明: 给对象属性赋值的操作:①属性的默认初始化-②显示初始化/③代码块中初始化(2和3哪个代码在前哪个先执行)-④构造器中初始化
2. 对象的内存布局
- 对象头(Header):如果是数组对象,还需记录数组长度
①运行时元数据(Mark Word):哈希值、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳
②类型指针:指向类元数据,确定该对象所属的类型- 实例数据(Instance Data):
存储对象真正的有效信息,包含程序代码中定义的各种类型的字段(包含父类继承下来的)
说明:相同宽度的字段总是分配在一起;父类中定义的变量会出现在子类之前;如果CompactFields参数为true,子类的窄变量可能插入到父类变量的空隙- 对齐填充(Padding):不是必须的,仅仅起到占位符的作用
3. 对象的访问定位
对象访问的方式
- 句柄访问
浪费内存,效率较低,对象移动,引用地址无需修改
- 直接指针(Hotspot采用)
节约空间,效率较高,对象移动,引用地址需要修改
六.直接内存(Direct Memory)
什么是直接内存?
- 不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范定义的内存区域
- 直接内存是在Java堆外的,直接向系统申请的内存区间
- 来源于NIO,通过存在堆中的DirectByteBuffer操作本地内存(IO与NIO?)
- 访问直接内存的速度优于Java堆,读写性能高:
读写频繁的场合考虑使用直接内存,Java的NIO库允许Java程序使用直接内存,用于数据缓冲区
非直接缓冲区:
直接缓冲区:
直接内存OOM(Direct buffer memory)
- 用于直接内存在堆外,因此不会受限于-Xmx设定的堆大小,但是系统内存是有限的,Java堆和直接内存的总和依然受限于操作系统的最大内存
- 缺点:分配回收成本较高,不受JVM内存回收管理
- 直接内存可以通过MaxDirectMemorySize设置
- 如果不指定大小,默认和堆的最大值-Xmx参数值一致