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

JVM对象创建全过程

JVM对象创建全过程深度解析

1. 对象创建的整体流程

JVM创建对象的过程可以分为7个关键步骤,从类检查到内存分配,再到对象初始化:

类加载检查 → 内存分配 → 内存空间初始化 → 对象头设置 → 构造函数执行 → 栈帧引用建立 → 对象使用

2. 详细创建步骤

2.1 类加载检查

  • 检查时机:遇到new指令时
  • 检查内容
    • 类是否已加载、解析和初始化
    • 未加载则执行类加载过程
  • 异常NoClassDefFoundError(类找不到)或ClassNotFoundException

2.2 内存分配

分配方式
分配方式原理适用场景
指针碰撞通过指针移动分配连续内存堆内存规整(Serial/ParNew)
空闲列表维护可用内存块列表分配堆内存不规整(CMS)
TLAB线程私有分配缓冲区(Thread Local Allocation Buffer)多线程环境减少竞争
内存分配关键参数
-XX:+UseTLAB              # 启用TLAB(默认开启)
-XX:TLABSize=512k         # 设置TLAB大小
-XX:+PrintTLAB            # 打印TLAB分配信息

2.3 内存空间初始化

  • 清零操作:将分配的内存空间初始化为零值
    • 数值类型:0
    • 布尔类型:false
    • 引用类型:null
  • 目的:保证对象字段不包含随机值

2.4 对象头设置

对象头包含三部分信息(以64位JVM为例):

  1. Mark Word(8字节):

    • 哈希码
    • GC分代年龄
    • 锁状态标志
    // HotSpot源码中的markOop定义
    union markOop {uintptr_t value;struct {uintptr_t locked:1;       // 锁标志位uintptr_t age:4;          // 分代年龄uintptr_t hash:31;        // 哈希码} bits;
    };
    
  2. Klass Pointer(4字节,压缩开启时):

    • 指向方法区的类元数据
  3. 数组长度(仅数组对象有,4字节)

2.5 实例数据填充

  • 按照字段类型和声明顺序存储

  • 字段对齐(通常按8字节对齐)

  • 字段重排序优化示例:

    class Reordered {byte b;     // 1字节long l;     // 8字节int i;      // 4字节
    }
    // 优化后内存布局:[long][int][byte]+3字节填充
    

2.6 构造函数执行

  • 执行方法(非
  • 初始化顺序:
    1. 父类构造器
    2. 实例变量初始化
    3. 构造器代码块

3. 对象内存布局示例

Object obj = new Object()为例(64位JVM开启压缩指针):

[对象头][Mark Word(8字节)]      : 0x0000000000000001 (无锁状态)[Klass Pointer(4字节)]   : 0x0000000100000000
[实例数据]                 : 无(Object类无实例字段)
[对齐填充(4字节)]          : 0x00000000
总大小:16字节

4. 对象访问定位方式

4.1 句柄访问

  • 原理:堆中维护句柄池,包含对象实例数据和类型数据指针
  • 优点:引用稳定(对象移动时只需更新句柄)
  • 缺点:多一次指针跳转

4.2 直接指针(HotSpot采用)

  • 原理:引用直接指向堆中对象
  • 优点:访问速度快(少一次指针跳转)
  • 缺点:对象移动时需要更新所有引用

5. 对象创建的性能优化

5.1 TLAB优化

  • 原理:每个线程预先分配一小块内存(默认占Eden区1%)

  • 查看TLAB使用

    jstat -gc <pid> | grep TLAB
    

5.2 逃逸分析与栈上分配

  • 优化条件

    • 对象未逃逸出方法
    • 支持标量替换(-XX:+EliminateAllocations)
  • 示例

    public void test() {User user = new User();  // 可能直接在栈上分配user.id = 1;System.out.println(user.id);
    }
    

6. 对象创建的字节码分析


// 源代码
Object obj = new Object();// 对应字节码
0: new           #2      // ① 创建对象
3: dup                 // ② 复制引用
4: invokespecial #1     // ③ 调用<init>
7: astore_1            // ④ 存储引用
  1. new:创建未初始化对象
  2. dup:复制引用(用于后续初始化和方法调用)
  3. invokespecial:调用构造函数
  4. astore:将引用存入局部变量表

7. 常见面试问题

7.1 new关键字背后发生了什么?

  • 类加载检查 → 内存分配 → 初始化 → 构造方法调用 → 返回引用

7.2 对象一定在堆上分配吗?

  • 不一定,可能通过栈上分配标量替换优化

7.3 如何证明对象内存布局?

  • 使用JOL工具:

    System.out.println(ClassLayout.parseInstance(obj).toPrintable());
    

8. 生产环境建议

  1. 监控对象创建速率

    jstat -gcutil <pid> 1000
    
  2. 优化小对象分配

    • 避免过度包装
    • 考虑对象复用(享元模式)
  3. 合理设置堆大小

    -Xms4g -Xmx4g -XX:NewRatio=2
    
http://www.xdnf.cn/news/93.html

相关文章:

  • 大模型面经 | DeepSpeed中ZeRO-1、ZeRO-2和ZeRO-3的区别是什么?
  • uniapp运行在app端如何使用缓存
  • 【ubuntu】在Linux Yocto的基础上去适配Ubuntu的wifi模块
  • 科技如何改变世界?
  • 微博辐射源和干扰机
  • Hadoop的三大结构及其作用
  • leetcode 309. Best Time to Buy and Sell Stock with Cooldown
  • 热门与冷门并存,25西电—电子工程学院(考研录取情况)
  • 如何在米尔-STM32MP257开发板上部署环境监测系统
  • Windows 图形显示驱动开发-WDDM 1.2功能—Windows 8 中的 DirectX 功能改进(五)
  • 什么是单元测试的“覆盖率”
  • 计算机视觉——基于使用 OpenCV 与 Python 实现相机标定畸变校正
  • 安全测试报告模板
  • PyTorch 浮点数精度全景:从 float16/bfloat16 到 float64 及混合精度实战
  • pnpm解决幽灵依赖问题
  • [Unity]-[UI]-[Prefab] 关于UGUI UI Prefab的制作技巧
  • C++: 类和对象(中)
  • 避免IP地址关联,多个手机设备的完美公网IP问题
  • Django ORM 定义模型
  • 【html】a标签target属性以及扩展应用
  • 2025TGCTF Web WP复现
  • 2025年03月中国电子学会青少年软件编程(Python)等级考试试卷(六级)答案 + 解析
  • 多线程编程的简单案例——单例模式[多线程编程篇(3)]
  • 前端零基础入门到上班:Day7——表单系统实战全解析
  • 文献总结:NIPS2023——车路协同自动驾驶感知中的时间对齐(FFNet)
  • node.js 基础
  • 9.Rust+Axum 测试驱动开发与性能优化全攻略
  • 韩媒专访CertiK创始人顾荣辉:黑客攻击激增300%,安全优先的破局之路
  • 在Vmware15(虚拟机免费) 中安装纯净win10详细过程
  • Google Gemini 系列AI模型 的详细解析,涵盖其技术特点、版本差异、应用场景及优势