0

0

Java中的对象是怎么创建的_new关键字在堆内存中的分配过程

P粉602998670

P粉602998670

发布时间:2026-03-18 13:38:51

|

721人浏览过

|

来源于php中文网

原创

new 关键字触发类加载检查、堆内存分配、零值初始化、对象头设置及构造方法执行;其中堆分配受GC策略、TLAB、大对象阈值等影响,对象头含Mark Word和Class Pointer,字段在构造前已分配默认值,逃逸分析可能使对象栈上分配或标量替换。

java中的对象是怎么创建的_new关键字在堆内存中的分配过程

new 关键字触发的堆内存分配步骤

Java 中 new 不是简单“划一块内存”就完事,它是一连串 JVM 层面的动作:类加载检查 → 分配内存 → 初始化零值 → 设置对象头 → 执行 <init></init> 方法。其中堆内存分配发生在第二步,且具体策略取决于垃圾收集器和堆布局。

常见错误现象:没报 OOM 却发现对象初始化慢、GC 频繁、或 OutOfMemoryError: Java heap space 突然出现——往往不是内存不够,而是分配策略失配(比如大对象直接进老年代触发 Full GC)。

  • 使用场景:高频创建小对象(如 DTO、临时集合)时,分配速度影响明显;大对象(>8KB,默认阈值)可能绕过 Eden 区,直接进入老年代
  • 参数差异:-XX:PretenureSizeThreshold 控制大对象直接入老年代的大小门槛;-XX:+UseTLAB(默认开启)让每个线程在 Eden 区预分配私有缓冲区,避免并发分配锁竞争
  • 性能影响:关闭 TLAB 后多线程频繁 new 会争抢 Eden 区指针,吞吐下降明显;而 TLAB 空间不足时,仍需同步分配,所以对象大小波动大会放大碎片问题

对象头里存了什么,为什么影响 new 的开销

每次 new 出来的对象,JVM 必须在堆上写入对象头(Object Header),至少包含 Mark Word 和 Class Pointer。这部分内存虽小(通常 12 或 16 字节),但它是分配后立即写入的强制操作,且 Mark Word 在锁升级、GC 标记、哈希码生成时还会动态变更。

容易踩的坑:以为对象刚 new 完就“稳定”了,其实 hashCode() 第一次调用会把 hash 值写进 Mark Word,如果此时对象正被其他线程标记为待回收,可能触发写屏障开销;另外,开启压缩指针(-XX:+UseCompressedOops)时,Class Pointer 占 4 字节而非 8 字节,能省空间但需额外解压运算。

立即学习Java免费学习笔记(深入)”;

  • Mark Word 内容随对象状态变化:无锁态存哈希码/分代年龄/锁标志位;轻量级锁态存指向栈中锁记录的指针
  • Class Pointer 指向方法区的类元数据,若类未加载,new 会先触发类加载过程,延迟对象创建
  • 64 位 JVM 下关闭压缩指针(-XX:-UseCompressedOops)会使对象头变大,间接增加 GC 扫描压力

构造函数执行前,字段已经存在但未必是你想的值

new 分配完内存并清零后,字段就有了默认值(int 是 0、Objectnull),但此时还没跑任何 Java 代码。构造函数里的逻辑(包括字段赋值、this 调用、super 调用)全在 <init></init> 方法里,属于分配完成后的独立阶段。

Buildt.ai
Buildt.ai

AI驱动的软件开发平台,可以自动生成代码片段、代码分析及其他自动化任务

下载

典型误用:在父类构造器中调用子类重写的方法(比如 this.doInit()),此时子类字段仍是默认值,导致 NPE 或计算错误——因为子类字段内存已分配、但尚未执行子类构造器里的赋值语句。

  • 字段初始化顺序固定:父类静态块 → 子类静态块 → 父类实例变量赋值 & 实例块 → 父类构造器 → 子类实例变量赋值 & 实例块 → 子类构造器
  • 编译器会把字段声明处的初始化(如 private List<string> list = new ArrayList();</string>)挪到构造器开头,紧挨着 super()this() 调用之后
  • 使用 Lombok 的 @Data@Builder 时,生成的构造器逻辑依赖字段声明顺序,字段循环引用会导致编译期或运行期异常

对象真的只在堆里吗?逃逸分析可能让它消失

JVM 并不保证所有 new 都落在堆上。当 JIT 编译器通过逃逸分析判定一个对象的引用不会离开当前方法或线程(即“不逃逸”),就可能直接将对象拆解成字段,分配在栈上(栈上分配)或者干脆优化掉(标量替换)。

这解释了为什么有些微基准测试里 new 速度极快——对象根本没进堆。但这个优化非常脆弱:只要对象被传给任意一个非内联方法、放入集合、或发布为静态变量,逃逸分析立刻失效,回归堆分配。

  • 开启条件:-XX:+DoEscapeAnalysis(JDK8 默认开启,JDK15+ 移除该选项,但优化仍存在)
  • 验证方式:加 -XX:+PrintEscapeAnalysis 看日志,或用 JMH + -prof gc 观察是否发生 GC
  • 注意:栈上分配不是“真在栈”,只是语义等价;且仅限于非逃逸的短生命周期对象,对 long-lived 对象无效

堆分配看似透明,但每一步都牵扯类加载、GC 策略、JIT 优化和硬件缓存行对齐。最常被忽略的是:你以为的“对象创建”其实跨了 JVM 多个子系统,任何一个环节卡住(比如类加载死锁、TLAB 耗尽、逃逸分析失败),都会让 new 表现出意料之外的延迟或内存行为。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

256

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1154

2024.03.01

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

256

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1154

2024.03.01

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

256

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1154

2024.03.01

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1091

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

619

2024.08.29

Python WebSocket实时通信与异步服务开发实践
Python WebSocket实时通信与异步服务开发实践

本专题聚焦 Python 在实时通信场景中的开发实践,系统讲解 WebSocket 协议原理、长连接管理、消息推送机制以及异步服务架构设计。内容包括客户端与服务端通信实现、连接稳定性优化、消息队列集成及高并发处理策略。通过完整案例,帮助开发者构建高效稳定的实时通信系统,适用于聊天应用、实时数据推送等场景。

3

2026.03.18

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.5万人学习

C# 教程
C# 教程

共94课时 | 11.5万人学习

Java 教程
Java 教程

共578课时 | 83.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号