Hotspot JVM 底层C/C++ 源码 入门4--oop-klass模型

Hotspot虚拟机在内部使用两组类来表示Java的类和对象

  • oop(ordinary object pointer),描述对象的实例信息
  • klass,描述java类,是虚拟机内部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可以在运行期获取类的信息

oopDesc

为所有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类的数据结构的内存位置

Hotspot JVM 底层C/C++ 源码 入门4--oop-klass模型_第1张图片

Handle模型

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();
}

klass和oop的转换

为了方便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));
}

 

你可能感兴趣的:(jvm)