网站首页 > 精选教程 正文
在 Java 中对象的创建方式有多种,最常见的就是通过 new 关键字,但是无论用什么方式,JVM 底层都是一样的。
1. 类加载检查
当代码中使用 new 关键字创建对象时,JVM 首先会检查所要创建对象的类是否已经被加载。如果该类尚未被加载,JVM 会启动类加载机制,按照类加载器的委托模型查找并加载相应的类。类加载过程分为加载、验证、准备、解析和初始化五个阶段。
2. 分配内存空间
一旦确认类已加载,JVM 就会为新对象分配内存空间。对象所需内存的大小在类加载完成后就已经确定。内存分配方式主要有两种:
- 指针碰撞:如果 Java 堆中的内存是规整的,即已使用的内存和未使用的内存分别在两端,中间有一个指针作为分界点。那么分配内存时,只需将指针向未使用的内存方向移动与对象大小相等的距离即可。比如带有内存整理过程的垃圾回收器(如 Serial、ParNew 等)在垃圾回收时会进行内存紧凑化操作,将堆内存整理成规整的状态。当堆内存经过这些垃圾回收器的内存整理操作后,就满足了指针碰撞的内存分配要求。此时,在分配新对象内存时,只需将分界指针向未使用的内存方向移动与对象大小相等的距离即可完成内存分配,无需进行额外的空闲内存块查找和管理,大大提高了内存分配的效率。
注意:指针碰撞是一种在内存规整情况下进行对象内存分配的高效方式,但在多线程环境下使用指针碰撞会引发并发问题。常见的解决方案有:
- CAS(compare and swap)
- 本地线程分配缓冲(Thread Local Allocation Buffer,TLAB)
- 空闲列表:如果 Java 堆中的内存不是规整的,已使用的内存和未使用的内存相互交错,那么 JVM 就需要维护一个记录哪些内存块是空闲的列表(free list)。分配内存时,从列表中找到一块足够大的空间划分给对象实例,并更新列表。这种方式适用于使用 CMS 这种基于标记清除 (Mark - Sweep) 算法的垃圾回收器,因为这种算法回收后会产生内存碎片。
3. 初始化零值
内存分配完成后,JVM 会将分配到的内存空间初始化为零值(不包括对象头)。这一步操作保证了对象的实例变量在 Java 代码使用之前就已经有了一个确定的初始值,比如 int 类型初始化为 0,boolean 类型初始化为 false,引用类型初始化为 null 等。这样做的好处是,当对象的构造函数中没有显式地对某些变量进行初始化时,也能保证其有一个默认的初始值,避免程序出现错误。
4. 设置对象头
在HotSpot虚拟机中,对象的内存布局可以分为 3 部分 :对象头(Header)、 实例数据(Instance Data)和对齐填充(Padding)。在初始化零值之后,JVM 会设置对象头信息。对象头包含两部分数据:
- 运行时元数据:例如对象的哈希码(HashCode)、对象的分代年龄、锁状态标志等信息。这些信息用于 JVM 在运行时对对象进行管理和操作,比如在垃圾回收过程中判断对象是否存活,在多线程环境下处理对象的锁机制等。
- 类型指针:指向对象所属类的元数据的指针,通过这个指针,JVM 可以知道该对象是哪个类的实例,从而能够调用该类的方法等。如果对象是一个数组,对象头中还会包含数组的长度。
对象结构
32 位 JVM 的 Mark Word
64 位 JVM 的 Mark Word
5. 执行方法
最后一步是执行对象的构造函数(init 方法)。JVM 会通过 <init> 方法完成最终初始化,该方法按顺序合并执行:成员变量显式赋值 → 实例代码块 → 构造函数逻辑。只有当整个 <init> 方法执行完毕后,对象才处于完全可用状态,此时引用变量才能安全访问该对象。
最后,来个图总结下
猜你喜欢
- 2025-05-02 轻松掌握Java多线程 - 第六章:volatile关键字
- 2025-05-02 为什么阿里巴巴Java开发手册禁止使用Executors创建线程池?
- 2025-05-02 linux:线程的3种实现方式(内核级,用户级和混合型)
- 2025-05-02 Java线程池核心参数调优指南:掌控并发世界的钥匙
- 2025-05-02 互联网大厂后端开发必看!Java 内部类 4 种实现方式深度解析
- 2025-05-02 Java多线程编程:一场与并发世界的奇妙冒险
- 2025-05-02 Java线程与并发:一场神奇的舞蹈(java线程是并行的吗)
- 2025-05-02 Java线程池的四种用法与使用场景(java线程池的原理和实现)
- 2025-05-02 网易面试:SpringBoot如何开启虚拟线程?
- 2025-05-02 探秘Java并发编程:解锁多线程世界的奇妙之旅
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)