全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-11 6 分钟 ✍️ juanwangdev

Java对象创建与内存分配

理解对象创建过程有助于理解JVM内存管理和性能优化。

对象创建流程

Java
┌─────────────┐
│ new指令     │
└─────────────┘
      ↓
┌─────────────┐
│ 类加载检查   │ ← 是否已加载
└─────────────┘
      ↓
┌─────────────┐
│ 分配内存     │ ← 堆中分配
└─────────────┘
      ↓
┌─────────────┐
│ 初始化零值   │ ← 默认值
└─────────────┘
      ↓
┌─────────────┐
│ 设置对象头   │ ← 元数据
└─────────────┘
      ↓
┌─────────────┐
│ 执行init方法 │ ← 构造器初始化
└─────────────┘
      ↓
┌─────────────┐
│ 返回引用     │
└─────────────┘

详解各步骤

1. 类加载检查

Java
Object obj = new Object();
// JVM检查Object类是否已加载、链接、初始化
// 若未加载,则执行类加载过程

2. 分配内存

两种分配方式

方式原理适用场景
指针碰撞移动指针分配堆内存规整(Serial、ParNew)
空闲列表从列表中选择空闲块堆内存不规整(CMS)

并发安全问题

方案描述
CAS + 失败重试保证更新原子性
TLABThread Local Allocation Buffer,每个线程独立分配区
Java
// JVM参数
-XX:+UseTLAB  // 启用TLAB

3. 初始化零值

Java
public class User {
    private int age;        // 初始化为0
    private boolean active; // 初始化为false
    private String name;    // 初始化为null
}

对象字段在构造器执行前已初始化为默认值

4. 设置对象头

对象头包含:

  • Mark Word:锁状态、GC年龄、哈希码
  • 类型指针:指向类元数据

5. 执行init方法

Java
public class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;  // 初始化
        this.age = age;
    }
}

// 构造器即为init方法,完成对象初始化

对象内存布局

Java
┌─────────────────────────────────┐
│           对象结构               │
├─────────────────────────────────┤
│  ┌─────────────────────────────┐│
│  │        对象头               ││
│  │  ┌─────────┬─────────┐      ││
│  │  │Mark Word│类型指针 │      ││
│  │  │  8字节  │  4/8字节│      ││
│  │  └─────────┴─────────┘      ││
│  └─────────────────────────────┘│
│  ┌─────────────────────────────┐│
│  │        实例数据             ││
│  │  对象字段(不定长度)        ││
│  └─────────────────────────────┘│
│  ┌─────────────────────────────┐│
│  │        对齐填充             ││
│  │  保证8字节对齐              ││
│  └─────────────────────────────┘│
└─────────────────────────────────┘

Mark Word结构

64位JVM Mark Word:

Java
┌────────────────────────────────────┐
│              Mark Word             │
├────────────────────────────────────┤
│ 无锁:   │ hashcode │ age │ 01     │
│ 偏向锁: │ threadID │ age │ 01     │
│ 轻量锁: │ lock record ptr │ 00    │
│ 重量锁: │ monitor ptr     │ 10    │
│ GC标记: │ 空              │ 11    │
└────────────────────────────────────┘

对象访问方式

方式描述特点
直接指针引用直接指向对象访问快,对象移动需更新引用
间接访问引用指向句柄,句柄指向对象引用稳定,对象移动只更新句柄
Java
// 直接指针(HotSpot使用)
reference → object

// 间接访问
reference → handle → object
          → class metadata

内存分配策略

对象优先在Eden分配

Java
Object obj = new Object();
// 大多数对象在Eden区分配
// Eden满时触发Minor GC

大对象直接进老年代

text
// 大对象参数
-XX:PretenureSizeThreshold=1MB  // 超过1MB直接进老年代

长期存活进老年代

text
// 年龄阈值
-XX:MaxTenuringThreshold=15  // GC年龄超过15进老年代

// Survivor区年龄计数
// 每次Minor GC年龄+1

动态年龄判定

text
// Survivor区对象总大小超过一半
// 年龄最大的对象进老年代

实际示例

text
public class ObjectCreationDemo {
    public static void main(String[] args) {
        // 创建对象
        User user = new User("张三", 25);

        /*
         * 创建过程:
         * 1. 检查User类是否加载
         * 2. 堆中分配内存(假设TLAB)
         * 3. 初始化零值:name=null, age=0
         * 4. 设置对象头
         * 5. 执行构造器:name="张三", age=25
         * 6. 返回引用给user变量
         */
    }
}

注意事项

对象分配默认在TLAB中,减少并发冲突

大对象避免在年轻代复制,直接进老年代

对象头大小影响内存占用,可用-XX:+UseCompressedOops压缩指针

理解对象创建有助于排查内存问题

要点总结

  1. 对象创建:类加载检查 → 分配内存 → 初始化零值 → 设置对象头 → 执行init
  2. 内存分配方式:指针碰撞(规整堆)或空闲列表(不规整堆)
  3. 对象结构:对象头 + 实例数据 + 对齐填充
  4. 分配策略:优先Eden,大对象直接老年代,长期存活进老年代
  5. HotSpot使用直接指针访问对象

📝 发现内容有误?点击此处直接编辑

← 上一篇 Java垃圾回收机制与算法
下一篇 → Java类加载机制与双亲委派模型
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库