Java 创建对象过程 & JVM 内存分配并发安全笔记

发布于:2025-07-06 ⋅ 阅读:(19) ⋅ 点赞:(0)

一、Java 创建对象的完整过程

Java 中通过 new 创建对象,其背后是 JVM 的一系列操作,主要包括:

1.1 类加载检查

当代码中出现 new 指令时,JVM 首先会检查这个类是否已经被加载、解析和初始化过。

  • 若未加载,会触发类加载过程(ClassLoader)。
  • 加载后才可以为该类分配内存。

1.2 分配内存

为新对象分配内存空间(位于堆内存),有两种方式:

分配方式 说明
指针碰撞(Bump-the-pointer) 如果内存是规整的(使用 Serial、ParNew 等),通过一个指针一直向后分配即可。
空闲列表(Free-list) 若堆空间不规整(比如 CMS),需要维护一个可用内存块的列表,找到合适位置进行分配。

1.3 并发安全保障(重点)

在多线程环境下,为对象分配内存可能出现竞争问题(多个线程争抢分配内存)。

JVM 采用了以下几种机制来保证内存分配的并发安全:

1)CAS + 失败重试
  • 指针碰撞方式下,使用 CAS(Compare-And-Swap)操作更新指针;
  • 若失败(因为有其他线程成功更新了),则重试,直到成功。
2)Tlab(Thread Local Allocation Buffer)线程本地分配缓冲区
  • 每个线程会在堆中分配一块小内存作为私有区域,称为 TLAB;
  • 在 TLAB 中分配对象几乎不需要加锁,效率高;
  • TLAB 用完再申请,或者直接走共享堆的 CAS 方式。

-XX:+UseTLAB 参数用于开启 TLAB(默认开启)。


1.4 对象初始化

JVM 完成内存分配后,会进行以下操作:

① 将分配的内存空间清零(不包括对象头)
② 设置对象头(包括哈希码、GC 分代年龄、类型指针等)
③ 执行 <init> 构造方法初始化对象内容

二、JVM 对象分配时的内存结构

对象内存结构包含:

  1. 对象头(Header)
    • Mark Word:存储哈希值、GC 信息、锁状态等;
    • Class Pointer:指向对象的类型元数据(即 class 对象);
  2. 实例数据(Instance Data)
    • 包含类中定义的字段内容;
  3. 对齐填充(Padding)
    • 为了满足内存对齐要求(通常是8字节倍数)。

三、对象创建的 JVM 字节码体现

使用 javap -v 类名.class 查看,可以发现:

new com.example.User
invokespecial #构造方法

其中:

  • new:分配内存并创建引用;
  • dup:复制栈顶引用;
  • invokespecial:调用构造方法初始化对象。

四、对象创建方式总结

方式 是否走构造函数 是否可控
new ✅ 是
Class.newInstance() ✅ 是 ❌(必须有无参构造)
Constructor.newInstance() ✅ 是 ✅(可选构造)
clone() ❌ 否(浅拷贝)
反序列化 ❌ 否(自动恢复)

五、拓展:逃逸分析与栈上分配

配合 JIT 编译器优化,对未逃逸的对象可优化为栈上分配,从而避免堆分配和 GC。

需开启参数:

-XX:+DoEscapeAnalysis
-XX:+EliminateAllocations

六、面试高频问题总结

Q1:Java 中 new 一个对象经历了哪些步骤?

  • 类加载检查;
  • 内存分配(TLAB/CAS);
  • 对象头初始化;
  • 构造函数初始化。

Q2:JVM 如何保证对象分配的并发安全?

  • TLAB 本地分配;
  • CAS 保证共享分配指针的原子性。

Q3:对象是一定分配在堆上吗?

不是。如果开启逃逸分析、对象未逃逸,有可能在栈上分配,提高效率。


参考

《深入理解Java虚拟机》 第三版 - 周志明
https://book.douban.com/subject/34907497/

OpenJDK 官方文档:对象分配与内存布局
https://openjdk.org/

TLAB 配置详解(Oracle 官方)
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

Java 内存模型 JSR-133 规范
https://jcp.org/en/jsr/detail?id=133

JVM 源码阅读参考(HotSpot)
https://github.com/openjdk/jdk


网站公告

今日签到

点亮在社区的每一天
去签到