摘要
HotSpot 是 Oracle JDK 和 OpenJDK 使用的默认 JVM 实现,其内部实现涉及大量的 C++ 代码和复杂的算法。本文深入探秘 HotSpot 的核心组件:Oop-Klass 二元模型、Mark Word 的位布局、C1/C2 编译器的实现、G1 的 Card Table 和 Remembered Set、以及运行时数据结构的内部表示。通过理解 HotSpot 的内部实现,你能够更深入地理解 JVM 的工作原理,做出更精准的性能调优决策。
一、Oop-Klass 模型
1.1 为什么需要 Klass
HotSpot 使用 Oop-Klass 二元模型来表示 Java 对象:
┌──────────────────────────────────────────────────────────────────┐ │ Oop-Klass 模型 │ ├──────────────────────────────────────────────────────────────────┤ │ │ │ Oop(Ordinary Object Pointer): │ │ - 表示对象实例的数据 │ │ - 包含对象的字段值 │ │ - 存在于堆中 │ │ │ │ Klass: │ │ - 表示 Java 类的元数据 │ │ - 包含类的结构、方法、虚函数表(vtable) │ │ - 存在于 Metaspace │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Oop (实例) │ ──→ │ Klass │ │ │ │ - Mark Word│ │ - vtable │ │ │ │ - 元数据指针 │ │ - 方法 │ │ │ │ - 实例数据 │ │ - 字段 │ │ │ └──────────────┘ └──────────────┘ │ │ │ └──────────────────────────────────────────────────────────────────┘1.2 C++ 代码实现
// oop.hpp - Oop 的基类classoopDesc{friendclassVMStructs;private:volatilemarkOop _mark;union_metadata{Klass*_klass;narrowKlass _compressed_klass;}_metadata;public:markOopmark()const{return_mark;}markOop*mark_addr(){return&_mark;}Klass*klass()const;Klass*klass_gap()const;// 对象头大小staticintheader_size(){returnsizeof(oopDesc)/HeapWordSize;}};// 类继承层次classoopDesc:publicMetaspaceObj{...};classinstanceOopDesc:publicoopDesc{...};// 普通对象classarrayOopDesc:publicoopDesc{...};// 数组二、Mark Word 详解
2.1 64 位 Mark Word 结构
// markOop.hpp - Mark Word 的 C++ 定义// 64 位无锁状态// +------------------------------------------------------------------+// | unused:25 | hash:31 | age:4 | biased_lock:1 | lock:2 | |// +------------------------------------------------------------------+// |<--------------------- header --------------------->|<--- mark word --->|// 偏向锁状态// +------------------------------------------------------------------+// | thread:54 | epoch:2 | age:4 | biased_lock:1 | lock:2 | |// +------------------------------------------------------------------+// 轻量级锁状态// +------------------------------------------------------------------+// | pointer to lock record:62 | lock:2 | |// +------------------------------------------------------------------+// 重量级锁状态// +------------------------------------------------------------------+// | pointer to monitor:62 | lock:2 | |// +------------------------------------------------------------------+// GC 标记状态// +------------------------------------------------------------------+// | no object:62 | lock:2 | |// +------------------------------------------------------------------+2.2 Mark Word 的锁状态
// markOop.hpp 中的锁状态定义enum{locked_value=0,unlocked_value=1,monitor_value=2,marked_value=3,biased_lock_pattern=5};三、Card Table 与 Remembered Set
3.1 Card Table
G1 使用 Card Table 来追踪老年代到年轻代的引用:
┌──────────────────────────────────────────────────────────────────┐ │ Card Table 结构 │ ├──────────────────────────────────────────────────────────────────┤ │ │ │ 堆内存(老年代): │ │ ┌────┬────┬────┬────┬────┬────┬────┬────┬────┐ │ │ │Card│Card│Card│Card│Card│Card│Card│Card│Card│ ... │ │ └────┴────┴────┴────┴────┴────┴────┴────┴────┘ │ │ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ │ │ 每个 Card 代表 512 字节 │ │ │ │ Card 状态: │ │ - clean:没有跨代引用 │ │ - dirty:有跨代引用(年轻代对象被老年代引用) │ │ │ └──────────────────────────────────────────────────────────────────┘3.2 Remembered Set
G1 使用 Remembered Set 记录跨 Region 的引用:
┌──────────────────────────────────────────────────────────────────┐ │ Remembered Set │ ├──────────────────────────────────────────────────────────────────┤ │ │ │ Region A(年轻代)中的对象引用 Region B(老年代)的对象: │ │ │ │ Region A 的 Remembered Set: │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ RSet: │ │ │ │ - Region B: [引用位置1, 引用位置2, ...] │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ 作用: │ │ - GC 时只扫描 RSet 中的引用,而非整个老年代 │ │ - 大大减少 GC 的扫描范围 │ │ │ └──────────────────────────────────────────────────────────────────┘四、总结
HotSpot VM 的内部实现是理解 JVM 工作原理的关键。Oop-Klass 二元模型、Mark Word 的位布局、Card Table 和 Remembered Set 都是 G1 和其他 GC 算法高效运行的基础。理解这些底层机制,能帮助你在调优时做出更精准的决策。
系列导航
- 上一篇:【JVM深度解析】第28篇:JVM发展史
- 下一篇:【JVM深度解析】第30篇:GraalVM与AOT编译
- 系列目录:JVM深度解析
参考资料
- HotSpot VM Sources
- Understanding HotSpot JVM Memory