学JVM的时候,一直对OOP-Klass体系不是很理解,在这里总结了一下,望大家指正
前言
HotSpot是基于c++实现,而c++是一门面向对象的语言,本身具备面向对象基本特征,所以Java中的对象表示,最简单的做法是为每个Java类生成一个c++类与之对应。但HotSpot JVM并没有这么做,而是设计了一个OOP-Klass Model
- 这里的 OOP 指的是 Ordinary Object Pointer (普通对象指针),它用来表示对象的实例信息,看起来像个指针,实际上是藏在指针里的对象(是一个指针,作为一个java对象头存在)
- Klass 则包含元数据和方法信息,用来描述Java类,是“类元信息”
之所以采用这个模型是因为HotSopt JVM的设计者不想让每个对象中都含有一个vtable(虚方法表),所以就把对象模型拆成klass和oop,其中oop中不含有任何虚方法,而Klass就含有虚函数表,可以进行method dispatch
• Klass表示Java类在JVM中的存在形式
• InstanceKlass表示类的元信息
• InstanceMirrorKlass表示类的Class对象对应的类元信息
• InstanceRefKlass表示强软弱虚等引用对象对应的类元信息
• ArrayKlass表示数组类的元信息
• TypeArrayKlass表示基本数组的类元信息
• ObjArrayKlass表示引用数组的类元信息
• oopDesc表示JAVA对象在JVM中的存在形式
• instanceOopDesc表示普通类对象
• arrayOopDesc表示数组类对象
• typeArrayOopDesc表示基本数组类对象
• objArrayOopDesc表示引用数组类对象
内容
OOP
oops,也就是jvm中的对象指针,有一个共同基类,叫做oopDesc,存储在堆中
class oopDesc {
friend class VMStructs;
private:
volatile markOop _mark;
union _metadata {
wideKlassOop _klass;
narrowOop _compressed_klass;
} _metadata;
}
class instanceOopDesc : public oopDesc {
}
class arrayOopDesc : public oopDesc {
}
instanceOopDesc和arrayOopDesc,都继承了oopDesc中的内容,分别用于普通对象的创建和数组对象的创建
包含两个部分:_mark,也就是我们常说的markword;以及_metadata,包含压缩和未压缩的指针,都指向了方法区中的instanceKlass,也就是类元信息
Klass
Klass及其子类对象用于表示java中类的类元信息,存储在方法区中
InstanceKlass
JVM在运行时,需要一种用来标识Java内部类型的机制。在HotSpot中的解决方案是:为每一个已加载的Java类创建一个instanceKlass对象,用来在JVM层表示Java类
InstanceKlass包含了Java运行时环境中类所需的所有数据信息,在类加载这一步,类加载器会将.class文件读入类加载器的class content,然后以InstanceKlass的形式写入JVM内存区域的方法区中
InstanceMirrorKlass
InstanceMirrorKlass是类所对应的Class对象(java.lang.Class)的InstanceKlass,是InstanceKlass的子类
提出一个问题,了解了上述之后,那么,JAVA对象是如何与Class对象建立映射的?
以下列图示来理解会简单很多
以Test test = new Test()
为例
这就可以回答上面的问题了,实例对象通过指向类元信息的指针找到方法区的InstanceKlass,再通过里面的_java_mirror字段定位到Class对象
JDK6及以前,静态变量放在InstanceKlass对象的末尾;JDK7及以后,变到了Class对象,也就是mirror对象的末尾
JVM实际实现中,InstanceKlass会用klassOopDesc包装,为方便理解,就不改了,直接称为InstanceKlass
注意:在JDK 7及后续版本中,Klassklass体系已不再使用,这里就不做介绍了
参考