欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > IT业 > JVM对象创建全过程

JVM对象创建全过程

2025/4/24 4:21:51 来源:https://blog.csdn.net/qian4517/article/details/147342343  浏览:    关键词: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
    

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词