Skip to content

04 - 对象分配与内存布局

定位: 从 new 指令到对象销毁 —— JVM 中对象的完整生命周期 面试高频度: ⭐⭐⭐⭐⭐

一、对象生命周期在 JVM 体系中的位置

类加载完成后,JVM 拥有了某个类的运行时元数据(方法区中)。接下来才是 Java 程序真正核心的工作:创建对象并使用它们

对象生命周期处于 JVM 运行流程的中枢:

  • 向上: 接收类加载的结果,在堆上实例化出具体对象
  • 向下: 对象最终被 GC 回收,释放堆空间
  • 横向: 对象内存布局决定了 JIT 的优化空间(逃逸分析、标量替换)
┌─────────────────────────────────────────────────────────────────────┐
│                JVM 中对象的完整生命周期                                │
│                                                                     │
│  ┌─────────┐    ┌──────────┐    ┌────────┐    ┌───────────────┐    │
│  │  创建    │    │  内存布局  │    │  访问   │    │    回收        │    │
│  │         │    │          │    │        │    │               │    │
│  │ new 指令 │──→ │ MarkWord │──→ │ 句柄   │──→ │ GC 判定不可达  │    │
│  │ 5步流程  │    │ KlassPtr │    │ 直接   │    │ 对象头 GC 标记 │    │
│  │ 内存分配 │    │ 实例数据 │    │ 指针   │    │ 空间被释放     │    │
│  │ 初始化   │    │ 对齐填充 │    │        │    │               │    │
│  └─────────┘    └──────────┘    └────────┘    └───────────────┘    │
│       ↑               ↑              ↑               ↑             │
│   04.1 对象        04.2 对象      04.3 对象       05 GC 机制       │
│   创建过程         内存布局        访问定位        对象回收          │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │              分配策略 (贯穿整个生命周期)                        │    │
│  │  TLAB · 栈上分配 · 逃逸分析 · 标量替换 · 大对象直接进老年代    │    │
│  └─────────────────────────────────────────────────────────────┘    │
│       ↑                                                             │
│   04.4 分配策略                                                     │
└─────────────────────────────────────────────────────────────────────┘

二、子专题导航

#主题面试频率核心内容
**对象创建过程**对象创建过程⭐⭐⭐⭐⭐类加载检查 → 内存分配(指针碰撞/空闲列表) → CAS/TLAB → 零值初始化 → 对象头设置 → <init> 执行
**对象内存布局**对象内存布局⭐⭐⭐⭐⭐MarkWord 8字节(锁状态/hashCode/GC age)、Klass Pointer(压缩指针)、实例数据排序、对齐填充
**对象访问定位**对象访问定位⭐⭐⭐⭐句柄访问 vs 直接指针访问(两种方式的优劣势对比)、HotSpot 的选择动机
**分配策略**分配策略专题⭐⭐⭐⭐⭐TLAB 并发分配、逃逸分析与栈上分配、标量替换、大对象直接进入老年代

三、核心考点速记

1. 对象创建的 5 步(最核心考点)

new 指令


① 类加载检查 ─→ 检查常量池中是否有类的符号引用 → 检查类是否已加载/解析/初始化
                    │ 未加载 → 先执行类加载流程 ([[02.1-类加载生命周期]])

② 分配内存 ───→ 指针碰撞 (GC 规整) 或 空闲列表 (GC 不规整)
    │             并发安全: TLAB (无锁) 或 CAS + 失败重试

③ 初始化零值 → 实例字段设为 0/null (保证创建对象的字段可预期)

④ 设置对象头 → MarkWord + Klass Pointer (+ 数组长度)

⑤ 执行 <init> → 开发者编写的构造函数 (唯一可控步骤)

2. MarkWord 结构 (64位 JVM)

无锁状态:
┌──────────────┬──────────────────────┬──────────┬──────┬─────────┬─────────┐
│  unused:25   │  identity_hashcode   │ unused:1 │ age  │ biased  │  lock   │
│              │      (31 bits)       │          │ (4b) │ (1b)    │  (2b)   │
└──────────────┴──────────────────────┴──────────┴──────┴─────────┴─────────┘

                                        GC 年龄仅 4 bit → 最大值 15
                                        → MaxTenuringThreshold 上限为 15

3. TLAB vs 栈上分配

特性TLAB (Thread Local Allocation Buffer)栈上分配 (Stack Allocation)
原理线程在 Eden 内预留私有缓冲区逃逸分析判定对象未逃逸 → 在栈帧或寄存器分配
同步开销TLAB 内零同步,TLAB 耗尽时 CAS完全不需要同步
回收方式GC 回收 (对象仍在堆上)方法返回时栈帧弹出即回收 (零 GC 开销)
触发条件默认开启C2 编译器 + 逃逸分析通过 (-XX:+DoEscapeAnalysis)
效果减少 CAS 竞争,高并发下 2-3 倍加速消除大量临时对象的堆分配和 GC 压力

4. 对象访问方式对比

句柄访问:                           直接指针访问 (HotSpot):
┌─────────┐                        ┌─────────┐
│reference│                        │reference│
└────┬────┘                        └────┬────┘
     ▼                                 ▼
┌─────────────────────┐          ┌──────────────────┐
│    句柄池 (Handle)   │          │    对象实例       │
│  ┌─────────────────┐│          │ ┌──────────────┐ │
│  │ 实例数据指针 ──────│──→ 对象  │ │ MarkWord    │ │
│  │ 类型数据指针 ──────│──→ 方法区│ │ KlassPtr ────│─→ 方法区元数据
│  └─────────────────┘│          │ │ 实例数据     │ │
└─────────────────────┘          │ └──────────────┘ │
                                  └──────────────────┘

四、面试高频追问一览

追问关联笔记频次
new 一个对象在 JVM 中发生了什么?**对象创建过程**极高
对象在内存中的布局结构?**对象内存布局**极高
MarkWord 包含哪些信息?**对象内存布局**极高
什么是压缩指针?为什么能压缩?**对象内存布局**
对象的 GC 年龄为什么最大 15?**对象内存布局**
HotSpot 用哪种对象访问方式?为什么?**对象访问定位**中高
什么是逃逸分析?什么是标量替换?**分配策略**极高
TLAB 是什么?为什么需要它?**分配策略**
什么对象会直接进入老年代?**分配策略**中高

📚 相关链接

  • **Java堆** — 堆的分代结构是对象分配的目标区域
  • **方法区与元空间** — Klass 指针指向方法区类元数据
  • **类加载生命周期** — 对象创建前必须先完成类加载
  • **垃圾收集器详解** — 不同 GC 影响分配方式(指针碰撞 vs 空闲列表)
  • **方法内联和逃逸分析** — JIT 逃逸分析的深入原理
  • ← 返回 **JVM文库设计文档**

Knowledge4J — Java 知识库