Hotspot虚拟机在内部使用两组类来表示Java的类和对象
typedef class oopDesc* oop;
typedef class instanceOopDesc* instanceOop;
typedef class arrayOopDesc* arrayOop;
typedef class objArrayOopDesc* objArrayOop;
typedef class typeArrayOopDesc* typeArrayOop;
class Klass;
class InstanceKlass;
class InstanceMirrorKlass;
class InstanceClassLoaderKlass;
class InstanceRefKlass;
class ArrayKlass;
class ObjArrayKlass;
class TypeArrayKlass;
一般来说,这几种模型分别由于描述Java类类型 和 类型指针(引用)
比如:
ClassA a = new ClassA();
JVM加载ClassA到方法区,创建一个instanceKlass来保存ClassA这个类对象的信息(变量,方法,父类..)即instanceKlass等价于java里的class对象.
而instanceOop这个“普通对象指针”对象中包含了一个字段,指向instanceKlass这个实例(oop-klass模型)
在JVM实例化ClassA时,会另外创建一个instanceOop,储存ClassA实例对象的成员变量,instanceOop中也有一个字段指向instanceKlass
通过这个指针,JVM可以在运行期获取类的信息
为所有oop对象的顶级父类
class oopDesc {
friend class VMStructs;
private:
volatile markOop _mark;
union _metadata {//注意是union
Klass* _klass;
narrowKlass _compressed_klass;
} _metadata;
// Fast access to barrier set. Must be initialized.
static BarrierSet* _bs;
//...
}
先不管VMStructs和_bs,oopDesc类只剩下两个成员变量_mark,_metadata(使用Klass*为例)
_mark是一种标记,线程状态,并发锁,GC信息
_metadata标记元数据(变量,方法,父类,接口...)java类在JVM解析字节码是会还原出java源代码所定义的数据结构信息并保留在内存中,比如反射,而_metadata便指向java类的数据结构的内存位置
class Handle VALUE_OBJ_CLASS_SPEC{
private:
oop* _handle;
//...
}
handle主要用于封装oop和klass,因此声明handle是直接讲oop或者klass传递进去,同时JVM执行java类的方法是最终也是通过handle拿到对应的oop和klass
inline Handle::Handle(oop obj){
if (obj == NULL){
_handle = NULL;
}else{
_handle = Thread::current()->handle_area()->allocate_handle(obj);
}
}
这个构造函数结构oop类型参数,将其保存到当前线程在堆申请的handleArea表中.
oop和klass被handle封装之后,JVM内部大部分堆oop和klass的函数调用都要经过Handle一次中间寻址,因此重载了->
oop non_null_obj() const{
assert(_handle != NULL,"resolving NULL handle");
return *_handle;
}
oop operator ->() const {
return non_null_obj();
}
为了方便GC回收,每一个klass实例都要封装位oop,具体为:先分配oop,接着将klass实例分配到oop对象头后面
Klass* klass_part() const {
return (Klass*)((address)this + klass_part_offset_in_bytes());
}
klassOop as_klassOop() const{
return (klassOop)(((char*)this) - sizeof(klassOopDesc));
}