JVM——简单了解 OOP-Klass 二分模型

OOP和klass的概念

HotSpot中采用了OOP-Klass模型,它是用来描述Java对象实例的一种模型

  • OOP或OOPS(Ordinary Object Pointer)指的是普通对象指针,主要职能是表示对象的实例数据,存储在堆里面
  • Klass用来描述对象实例的具体类型,实现语言层面的Java类,存储在元空间(方法区)

总体上是多个OOP和一个Klass是对应的. 相当于一个类可以有多个实例

A a  = new A() ;  A a1 = new A();

a,a1 分别对应着不同的OOP, 对应着同一个Klass

OOP 源码

首先看 oopsHierarchy.hpp 文件中,可以看到在 OpenJDK 的源码中都是用 oopDesc* 等 Desc* 来表示的。

列出的是整个Oops模块的组成结构,其中包含多个子模块。每一个子模块对应一个类型,每一个类型的OOP都代表一个在JVM内部使用的特定对象的类型。

//定义了oops共同基类
typedef class   oopDesc*                            oop;
//表示一个Java类型实例
typedef class   instanceOopDesc*            instanceOop;
//表示一个Java方法
typedef class   methodOopDesc*                    methodOop;
//表示一个Java方法中的不变信息
typedef class   constMethodOopDesc*            constMethodOop;
//记录性能信息的数据结构
typedef class   methodDataOopDesc*            methodDataOop;
//定义了数组OOPS的抽象基类
typedef class   arrayOopDesc*                    arrayOop;
//表示持有一个OOPS数组
typedef class   objArrayOopDesc*            objArrayOop;
//表示容纳基本类型的数组
typedef class   typeArrayOopDesc*            typeArrayOop;
//表示在Class文件中描述的常量池
typedef class   constantPoolOopDesc*            constantPoolOop;
//常量池告诉缓存
typedef class   constantPoolCacheOopDesc*   constantPoolCacheOop;
//描述一个与Java类对等的C++类
typedef class   klassOopDesc*                    klassOop;
//表示对象头
typedef class   markOopDesc*                    markOop;

 

oopDesc结构

class oopDesc {
  friend class VMStructs;
 private:
  volatile markOop  _mark;
  union _metadata {
    wideKlassOop    _klass;
    narrowOop       _compressed_klass;
  } _metadata;
}

在Java程序运行过程中,每创建一个新的对象,在JVM内部就会相应地创建一个对应类型的OOP对象。在HotSpot中,根据JVM内部使用的对象业务类型,具有多种oopDesc的子类。除了oppDesc类型外,opp体系中还有很多instanceOopDescarrayOopDesc 等类型的实例,他们都是oopDesc的子类。

这些OOPS在JVM内部有着不同的用途,例如instanceOopDesc表示类实例,arrayOopDesc表示数组。也就是说,当我们使用new创建一个Java对象实例的时候,JVM会创建一个instanceOopDesc对象来表示这个Java对象。同理,当我们使用new创建一个Java数组实例的时候,JVM会创建一个arrayOopDesc对象来表示这个数组对象。

instanceOopDesc结构

class instanceOopDesc : public oopDesc {
}
 
class arrayOopDesc : public oopDesc {
}

 通过上面的源码可以看到,instanceOopDesc实际上就是继承了oopDesc,并没有增加其他的数据结构,也就是说instanceOopDesc中包含两部分数据:markOop _markunion _metadata

这里就和java对象头对起来了。

friend class VMStructs;
friend class JVMCIVMStructs;
private:
// 看 MarkOop 的内容
volatile markOop _mark;
// 存储对象描述数据的指针
union _metadata {
Klass*   _klass;
narrowKlass _compressed_klass;
} _metadata;

MarkOop 结构

  • hash: 保存对象的哈希码
  • age: 保存对象的分代年龄
  • biased_lock: 偏向锁标识位
  • lock: 锁状态标识位
  • JavaThread* 保存持有偏向锁的线程 ID
  • epoch: 保存偏向时间戳

XyANzb

klass体系

//klassOop的一部分,用来描述语言层的类型
class  Klass;
//在虚拟机层面描述一个Java类
class   instanceKlass;
//专有instantKlass,表示java.lang.Class的Klass
class     instanceMirrorKlass;
//专有instantKlass,表示java.lang.ref.Reference的子类的Klass
class     instanceRefKlass;
//表示methodOop的Klass
class   methodKlass;
//表示constMethodOop的Klass
class   constMethodKlass;
//表示methodDataOop的Klass
class   methodDataKlass;
//最为klass链的端点,klassKlass的Klass就是它自身
class   klassKlass;
//表示instanceKlass的Klass
class     instanceKlassKlass;
//表示arrayKlass的Klass
class     arrayKlassKlass;
//表示objArrayKlass的Klass
class       objArrayKlassKlass;
//表示typeArrayKlass的Klass
class       typeArrayKlassKlass;
//表示array类型的抽象基类
class   arrayKlass;
//表示objArrayOop的Klass
class     objArrayKlass;
//表示typeArrayOop的Klass
class     typeArrayKlass;
//表示constantPoolOop的Klass
class   constantPoolKlass;
//表示constantPoolCacheOop的Klass
class   constantPoolCacheKlass;

oopDesc是其他oop类型的父类一样,Klass类是其他klass类型的父类。

Klass向JVM提供两个功能:

  • 实现语言层面的Java类(在Klass基类中已经实现)

  • 实现Java对象的分发功能(由Klass的子类提供虚函数实现)

HotSopt JVM的设计者把对象一拆为二,分为klassoop,其中oop的职能主要在于表示对象的实例数据(是一个指针,作为一个java对象头存在),所以其中不含有任何虚函数。而klass为了实现虚函数多态,所以提供了虚函数表。所以,关于Java的多态,其实也有虚函数的影子在。

_metadata是一个共用体,其中_klass是普通指针,_compressed_klass是压缩类指针。这两个指针都指向instanceKlass对象,它用来描述对象的具体类型。

instanceKlass

JVM在运行时,需要一种用来标识Java内部类型的机制。在HotSpot中的解决方案是:为每一个已加载的Java类创建一个instanceKlass对象,用来在JVM层表示Java类。

来看下instanceKlass的内部结构:(将class文件相应数据读取到元空间所表现的形式

  //类拥有的方法列表
  objArrayOop     _methods;
  //描述方法顺序
  typeArrayOop    _method_ordering;
  //实现的接口
  objArrayOop     _local_interfaces;
  //继承的接口
  objArrayOop     _transitive_interfaces;
  //域
  typeArrayOop    _fields;
  //常量
  constantPoolOop _constants;
  //类加载器
  oop             _class_loader;
  //protected域
  oop             _protection_domain;
      ....

注意:

在JVM中,对象在内存中的基本存在形式就是oop。那么,对象所属的类,在JVM中也是一种对象,因此它们实际上也会被组织成一种oop,即klassOop。同样的,对于klassOop,也有对应的一个klass来描述,它就是klassKlass,也是klass的一个子类。klassKlass作为oop的klass链的端点。

关于对象和数组的klass链大致如下图:

内存存储

对象的实例(instantOopDesc)保存在堆上,对象的元数据(instantKlass)保存在方法区,对象的引用保存在栈上。

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,对象对应的java.lang.Class的OOP,这两个在堆上,还有在元空间的instanceklass。

 

 

 

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值