当前位置: 首页 > ai >正文

Java中new的相关知识

在 Java 中,new关键字是创建对象的核心方式,其本质是触发 JVM 在堆内存中为对象分配空间并完成初始化。这个过程涉及类加载、内存分配、初始化等多个环节,下面详细拆解其底层机制:

一、前置检查:类加载验证

new执行前,JVM 会先确认目标类是否已被加载到方法区(JDK8 + 为元空间)。如果类未加载,会触发类加载过程(加载→验证→准备→解析→初始化):

  • 加载:通过类全限定名读取字节码文件(.class)到内存;
  • 验证:确保字节码符合 JVM 规范(如格式正确、无安全隐患);
  • 准备:为类的静态变量分配内存并设置默认零值(如static int a默认 0);
  • 解析:将符号引用(如类名、方法名)转换为直接引用(内存地址);
  • 初始化:执行静态代码块和静态变量的显式赋值(如static int a = 10)。

只有类加载完成后,JVM 才知道该类的对象需要占用多少内存(实例变量的类型和数量已确定)。

二、核心步骤:堆内存分配

类加载完成后,new的核心动作是在堆内存中为新对象分配空间,空间大小由类的实例变量(非静态字段)决定(如int占 4 字节,Object引用占 4/8 字节,依 JVM 位数而定)。

内存分配有两种主流方式,取决于堆内存是否连续:

1. 指针碰撞(Bump The Pointer)

适用于堆内存无碎片的场景(如采用 “标记 - 复制” 算法的 GC 收集器:Serial、ParNew 等)。

  • 原理:堆中已用内存和空闲内存之间有一个指针,分配时只需将指针向空闲内存方向移动 “对象大小” 的距离,即可完成分配。
  • 示例:假设指针当前指向地址 1000,新对象需 200 字节,则指针移动到 1200,1000~1200 的空间分配给新对象。
2. 空闲列表(Free List)

适用于堆内存有碎片的场景(如采用 “标记 - 清除” 算法的 GC 收集器:CMS)。

  • 原理:JVM 维护一个 “空闲列表”,记录堆中所有空闲内存块的地址和大小。分配时从列表中找到一块足够大的空闲块,分割出 “对象大小” 的空间分配给新对象,剩余部分仍保留在列表中。

三、并发安全:解决分配冲突

多线程同时用new创建对象时,可能出现 “指针移动冲突”(如两个线程同时操作同一指针)。JVM 通过两种方式保证线程安全:

1. CAS + 失败重试

对内存分配动作加同步锁:通过CAS(Compare And Swap) 机制检查指针是否被其他线程修改,若未修改则成功分配,若已修改则重试,直到成功。

2. TLAB(本地线程分配缓冲)

JVM 为每个线程在堆中预先分配一块私有内存(TLAB,Thread Local Allocation Buffer)。

  • 线程创建对象时,优先在自己的 TLAB 中分配内存,避免线程间竞争;
  • 当 TLAB 用完时,才通过 CAS 从堆的公共区域分配新的 TLAB。
  • 可通过-XX:+UseTLAB开启(默认开启),-XX:TLABSize设置大小。

四、内存初始化:零值填充

内存分配完成后,JVM 会将分配到的空间(除对象头外)全部初始化为零值(如int→0,boolean→false,Object引用→null)。

  • 这一步是 “默认值” 的来源:即使实例变量未显式赋值,也能保证有合理的初始状态(如class A { int x; }中,new A().x默认 0)。

五、对象头设置(Object Header)

内存初始化后,JVM 会为对象设置对象头(占 8/16 字节,依 JVM 位数和对象类型而定),包含两类信息:

  1. 运行时数据:哈希码(HashCode)、GC 分代年龄(对象经历 GC 的次数)、锁状态标志(是否被同步锁持有)等;
  2. 类型指针:指向对象所属类的元数据(在方法区),用于确定对象的类型(如obj.getClass()的底层依据)。

特殊情况:如果是数组对象,对象头还会额外存储数组长度(因为数组的大小在编译期不确定,需运行时记录)。

六、执行构造方法(<init>)

最后,JVM 会调用对象的构造方法(字节码层面的<init>方法),完成以下操作:

  • 执行实例变量的显式赋值(如int x = 10);
  • 执行构造方法中的代码逻辑(如初始化其他对象、计算等)。

至此,一个完整可用的对象创建完成,new表达式返回该对象在堆中的引用(存储在栈中,或作为其他对象的字段)。

总结:new分配内存的完整流程

  1. 检查类是否加载→未加载则触发类加载;
  2. 在堆中分配内存(指针碰撞 / 空闲列表);
  3. 解决并发冲突(CAS 重试 / TLAB);
  4. 内存空间零值初始化;
  5. 设置对象头(运行时数据 + 类型指针);
  6. 执行构造方法(<init>),返回对象引用。

这个过程由 JVM 自动管理,开发者无需手动操作内存,体现了 Java “内存安全” 的特性。

http://www.xdnf.cn/news/17459.html

相关文章:

  • TDengine IDMP 快速体验(方式二 通过 docker)
  • 系统测试讲解 - Java使用selenium实现滑块验证的处理详解
  • Qt 框架全面解析:从基础到应用
  • 亚麻云之静态资源管家——S3存储服务实战
  • 在Word和WPS文字一页中实现一栏与多栏混排
  • 瑞芯微 RK3588 平台驱动开发 学习计划
  • OpenEnler等Linux系统中安装git工具的方法
  • 机器学习-----K-means算法介绍
  • 数据类型全解析
  • PostgreSQL因为A/B switch以及group表过多导致WAL full的情况讨论
  • 冒泡排序实现以及优化
  • django基于Python的设计师作品平台的数据可视化系统设计与实现
  • 数字图像处理2——图像增强
  • Java设计模式之开闭原则介绍与说明
  • TypeScript中的type和interface的区别是什么?
  • 红楼梦文本数据分析
  • LeetCode 869.重新排序得到 2 的幂:哈希表+排序(一次初始化)
  • 前端开发的奇技淫巧 --- 持续更新中
  • 使用线性降维方法进行数据降维
  • 使用tcp ntrip 协议 接收数据报错 java.net.SocketException: Connection reset
  • MariaDB 数据库管理与web服务器
  • 变量详解:创建初始化与内存管理
  • 【数据结构入门】栈和队列的OJ题
  • Virtio 驱动关键结构体与函数详解
  • RabbitMQ面试精讲 Day 18:内存与磁盘优化配置
  • 01.【面试题】在SpringBoot中如何实现多数据源配置
  • UNet改进(31):基于Adaptive Attention的UNet设计与实践
  • 智慧社区(十一)——Spring Boot 实现 Excel 导出、上传与数据导入全流程详解
  • 【永磁同步电机数学模型全程推导】【7 转矩方程】
  • IntelliJ IDEA 2025.2 重磅发布