前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >HotSpot JVM中Klass/oopDesc/oop的作用与关系

HotSpot JVM中Klass/oopDesc/oop的作用与关系

作者头像
KINGYT
发布2023-03-15 13:54:44
6480
发布2023-03-15 13:54:44
举报

Klass的继承关系图

oopDesc的继承关系图

oop与oopDesc的关系图


JVM中,Klass代表一个Java类,oopDesc代表一个Java对象(其实只代表其头部信息),oop代表一个指向oopDesc的指针(即指向Java对象的指针)。

Klass的子类中,InstanceKlass代表一个普通的Java类(比如我们自定义的一个Java类),ArrayKlass代表数组类型的Java类(该Java类是JVM内部自动创建的,由数组维数和数组基础类型唯一确定)。

InstanceKlass的子类中,InstanceClassLoaderKlass代表的Java类是java.lang.ClassLoader,InstanceMirroKlass代表的Java类是java.lang.Class,InstanceRefKlass代表的Java类是java.lang.ref.Reference及其子类。由于JVM内部会对这三个Java类做特殊处理,所以内部也提取出了对应的InstanceKlass类。

ArrayKlass的子类中,TypeArrayKlass代表的是Java基础数据类型的一维数组所对应的类,比如int[].class、long[].class等,ObjArrayKlass代表的是对象类型的数组所对应的类,比如String[].class、Object[][].class等。这里需要特殊指出的是,int[]数组在Java内部其实也是一个Java对象,所以int[][].class对应的Klass是ObjArrayKlass,而不是TypeArrayKlass。

oopDesc的子类中,arrayOopDesc代表的是数组类型的对象,InstanceOopDesc代表的是普通Java类的对象,markOopDesc并不是代表一个Java对象,它只是因为历史原因被放到了这个继承关系里。

arrayOopDesc的子类中,objArrayOopDesc代表的是对象类型的数组,typeArrayOopDesc代表的是Java基础数据类型的一维数组。


当JVM加载或定义一个Java类时,它会在内部创建一个对应的Klass对象,用来存放该Java类的各种信息。而在该Klass对象创建过程中,它同时也会计算该Klass对象对应的Java类所创建的Java对象需要多大内存空间,该计算结果会被保存到Klass对象中的_layout_helper字段中,这样当运行时需要创建Java对象时,直接根据这个字段的值分配一块内存就好了。

InstanceKlass的计算规则大体上是 sizeof(instanceOopDesc) + 父类中非静态字段占用内存大小 + 该类中非静态字段占用内存大小。

ArrayKlass的计算规则大体上是 sizeof(arrayOopDesc) + sizeof(int) 用来存放数组长度 + 要分配的数组长度 * 数组元素所占内存大小。

InstanceMirrorKlass因为对应的Java类是java.lang.Class,所以它的计算规则很特殊,我们这里详细描述下。

首先,我们来想下创建java.lang.Class对象的用途是什么?

对,用来存放有关类的一些信息,比如类名等。

那什么时候需要创建它呢?

在类被加载或定义的时候,也就是在创建Klass对象的时候。

那既然已经有Klass对象了,为什么还要创建个java.lang.Class类型的Java对象呢?

因为Java对象有个getClass方法,需要返回其所属类对应的Java对象,这样可以在Java程序中获取Java类相关信息。

那这个java.lang.Class对象会有什么字段呢?

该对象会包含java.lang.Class类及其父类里所有非静态字段。

还包括其他字段吗?

还包括发起创建该对象对应的Java类中静态字段。

通过以上几个问答,现在我们可以比较清楚的知道,在Java类加载或定义过程中,会创建一个Klass对象,作为该Java类在JVM内部的代表,同时也会创建一个java.lang.Class类型的Java对象,作为该Java类在Java程序内的代表(该对象会被保存在Klass对象的_java_mirror字段中)。而这个java.lang.Class对象包含的字段为java.lang.Class类及其父类里所有非静态字段,加上发起创建该java.lang.Class对象对应的Java类中静态字段。

综上,InstanceMirrorKlass对象占用内存大小的计算规则大体上为:sizeof(instanceOopDesc) + java.lang.Class父类中非静态字段占用内存大小 + java.lang.Class类中非静态字段占用内存大小 + 发起创建该对象对应的Java类中静态字段占用内存大小。


创建普通Java对象对应的字节码为 new,对应的oop为instanceOop。

创建Java基础数据类型的一维数组对应的字节码为 newarray,对应的oop为typeArrayOop。

创建其他类型的一维数组或多维数组(该多维数组只有第一维指定了长度)对应的字节码为 anewarray,对应的oop为ObjArrayOop。

创建多维数组并且每一维都指定了具体长度对应的字节码为 multianewarray,对应的oop为ObjArrayOop。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-02-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 卯时卯刻 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档