1 概述
HotSpot是基于c++实现,而c++是一门面向对象的语言,本身具备面向对象基本特征,所以Java中的对象表示,最简单的做法是为每个Java类生成一个c++类与之对应。
但HotSpot JVM并没有这么做,而是设计了一个OOP-Klass Model。这里的 OOP 指的是 Ordinary Object Pointer (普通对象指针),它用来表示对象的实例信息,看起来像个指针实际上是藏在指针里的对象。而 Klass 则包含元数,用来描述Java类。
之所以采用这个模型是因为HotSopt JVM的设计者不想让每个对象中都含有一个vtable(虚函数表),所以就把对象模型拆成klass和oop,其中oop中不含有任何虚函数,而Klass就含有虚函数表,可以进行method dispatch(方法调度)。
OOP(Ordinary Object Pointer)所指向的是堆中的对象
对象的Klass指针指向instanceKlass,instanceKlass是类的元数据,在元空间中
instanceKlass中的_java_mirror指针指向堆中的Class对象(即类的Java镜像)
2 OOP-Klass模型
2.1 Klass
Klass简单的说是Java类在HotSpot中的c++对等体,用来描述Java类。
- Klass主要有两个功能:
- 实现语言层面的Java类
- 实现Java对象的分发功能
那Klass是什么时候创建的呢?一般jvm在加载class文件时,会在方法区创建instanceKlass,表示其元数据,包括常量池、字段、方法等。
注
(1)instanceKlass其实是Klass的一个对象,表示类的元数据Klass定义的结构如下:
- _layout_helper:描述对象整体布局
- _name:表示类名
- _java_mirror:表示Klass的Java层镜像类(指向堆中的Class对象,表示类的Java镜像)
- _super:表示父类
- _subklass:表示第一个子类
- next_slibling:指向的是下一个兄弟节点,JVM通过_subklass->next_slibling可以找到下一个子类
(2)instanceKlass实例信息的结构如下(即为instanceKlass就是用来描述类,即为类的元数据):
(3)从JDK 1.3到JDK 6的HotSpot VM,静态变量保存在类的元数据(InstanceKlass)的末尾。而从JDK 7开始的HotSpot VM,静态变量则是保存在类的Java镜像(java.lang.Class实例)的末尾。在HotSpot VM中,对象、类的元数据(InstanceKlass)、类的Java镜像,三者之间的关系是这样的:
即InstanceKlass中的_java_mirror指针指向了堆中Class对象(类的java镜像)。每个Java对象的对象头里,_klass字段会指向一个VM内部用来记录类的元数据用的InstanceKlass对象;InsanceKlass里有个_java_mirror字段,指向该类所对应的Java镜像----java.lang.Class实例。HotSpot VM会给Class对象注入一个隐藏字段“klass”,用于指回到其对应的InstanceKlass对象。这样,klass与mirror之间就有双向引用,可以来回导航。这个模型里,java.lang.Class实例并不负责记录真正的类元数据,而只是对VM内部的InstanceKlass对象的一个包装供Java的反射访问用。
2.2 OOP
Klass是在class文件在加载过程中创建的,OOP则是在Java程序运行过程中new对象时创建的。
一个OOP对象包含以下几个部分:
- instanceOopDesc,也叫对象头
- Mark Word,主要存储对象运行时记录信息,如hashcode, GC分代年龄,锁状态标志,线程ID,时间戳等
- 元数据指针,即指向方法区的instanceKlass实例
- 实例数据
- 对齐的字节(整个对象必须8字节对齐)
注:
(1)instanceOopDesc(对象头)其实是OopDesc的实例,OopDesc的结构如下:
oopDesc中包含两个数据成员:_mark 和 _metadata。其中markOop类型的_mark对象表示的是前面讲到的Mark World。_metadata是一个共用体,其中_klass是普通指针,_compressed_klass是压缩类指针,它们就是前面讲到的元数据指针,这两个指针都指向instanceKlass对象,它用来描述对象的具体类型。
3 实例说明
假如我们有如下代码:
class Model
{
public static int a = 1;
public int b;
public Model(int b) {
this.b = b;
}
}
public static void main(String[] args) {
int c = 10;
Model modelA = new Model(2);
Model modelB = new Model(3);
}
上述代码得OOP-Klass模型入下所示:
总结
当我们执行new Object()的时候,首先JVM native层判断该类是否被加载过,没有的话就进行类的加载,并在JVM内部创建一个instanceKlass对象表示该类的运行时元数据(Java层的Class对象),到初始化的时候,JVM就创建一个instanceOopDesc对象(对象头)表示该对象的实例,然后进行Mark Word信息填充,将元数据指针指向Klass对象,并填充实例变量。
部分转载自: http://blog.csdn.net/linxdcn/article/details/72850375.
推荐阅读: https://www.zhihu.com/question/50258991. RednaxelaFX
大佬