创建流程

对象的创建方法有很多 包括不限于 new ,clone,反序列化,反射构造等。

这里只讨论的是 “无中生有” 产生的对象

  • 通过new关键字生成对象;

  • 通过Class类的newInstance方法生成对象;

  • 通过Constructor类的newInstance方法生成对象;

在创建对象时 JVM 会经历以下流程

在设置对象基本信息后 JVM 角度来看,这个对象已经被创建完成了。在Java程序角度来看这个对象才刚刚开始。

一般来说 new 指令后面会跟随着 invokespecial 指令 (这个具体得看在那些环境中 new函数是如此)

为对象分配内存

在对象被加载后 这个对象所占的内存就已经可以被确定了

分配过程实际上就是把一块确定大小的内存进行分割,分配给某个对象

两种分配内存的策略

  1. 指针碰撞 Bump The Pointer

假设内存地址是连续的 左侧是未分配 右侧是已分配 分配一个对象 就把指针向右移动多少内存地址

要求内存地址连续,并且在并发情况下不能保证线程安全

  1. 空闲列表 Free List

实际上就是将内存块进行统计 制作一个 表单

然后在需要内存的时候选择一个大小合适的内存进行分配

如何解决线程安全?

  1. 对分配内存空间的动作进行同步处理,利用CAS机制实现失败重试,保证更新操作原子性

  2. 把分配内存的动作按照线程划分在不同的空间中进行,每个线程在堆中都分配一个缓冲区,在需要内存的时候优先使用缓冲区内的内存,如果缓冲区内的内存都用完了,才会进行同步锁定

对象的内存布局

如何定位到对象

在对象头中包含了一个数据:类型指针 但是这个类型指针不一定真的指向类型

他分为两种形式

  1. 句柄形式

如果采用句柄形式 那么会在 Java堆 中划分出一块区域作为 句柄池 通过句柄来连接对象与 reference 数据

句柄形式的好处就是在对象移动的时候(例如GC)只会改变句柄中实例数据的指针 不会改变 reference 数据

  1. 直接形式

直接形式的好处就是 速度会更快 节省了重定向的开销

HostSpot就是采用的直接形式

关于 Reference

reference 数据的作用

  • 间接访问对象: reference 数据允许程序通过引用来访问对象,而不是直接访问对象的内存地址。

  • 对象共享: 多个 reference 数据可以指向同一个对象,实现对象共享。

  • 垃圾回收: JVM 通过跟踪 reference 数据来判断对象是否被引用,从而进行垃圾回收。

reference 数据类型:

  • 强引用 (Strong Reference): 最常见的引用类型,只要强引用存在,对象就不会被垃圾回收。

  • 软引用 (Soft Reference): 当内存不足时,软引用指向的对象会被垃圾回收。

  • 弱引用 (Weak Reference): 当垃圾回收器进行垃圾回收时,弱引用指向的对象会被回收。

  • 虚引用 (Phantom Reference): 虚引用最弱,它不会影响对象的生存周期,主要用于跟踪对象的回收状态。

reference 数据的存储:

reference 数据存储在 JVM 的堆栈中,具体位置取决于 reference 数据的声明位置:

  • 局部变量: 存储在方法的栈帧中。

  • 成员变量: 存储在堆中的对象实例中。