我们继续接着上一篇 HotSpot的类模型(3)分析,这次主要分析表示java数组的C++类。

4、ArrayKlass

ArrayKlass继承自Klass,是所有数组类的抽象基类,类及重要属性的定义如下:

class ArrayKlass: public Klass {
...
private:
int _dimension; // This is n'th-dimensional array.
Klass* volatile _higher_dimension; // Refers the (n+1)'th-dimensional array (if present).
Klass* volatile _lower_dimension; // Refers the (n-1)'th-dimensional array (if present).
int _vtable_len; // size of vtable for this klass
oop _component_mirror; // component type, as a java/lang/Class
...
}

在Klass的基础上增加的属性如下表所示。

字段 作用
_dimension int类型,表示数组的维度,记为n
_higher_dimension Klass指针,表示对n+1维数组Klass的引用
_lower_dimension Klass指针,表示对n-1维数组Klass的引用
_vtable_len int类型, 虚函数表的长度
_component_mirror oop, 数组元素对应的java/lang/Class对象的Oop

_vtable_len的值为5,因为数组是引用类型,父类为Object类,而Object类中有5个虚方法可被用来继承和重写,如下:

  • void finalize()
  • boolean equals(Object)
  • String toString()
  • int hashCode()
  • Object clone()

_dimension、_higher_dimension与_lower_dimension对于一维及多维数组的描述非常重要,属性值的设置相对简单,这里不在介绍。

5、ArrayKlass类的子类

(1)TypeArrayKlass类

TypeArrayKlass是ArrayKlass的子类,用于表示数组元素是基本类型的数组

class TypeArrayKlass : public ArrayKlass {
...
private:
jint _max_length; // maximum number of elements allowed in an array
...
}

_max_length表示该数组允许的最大长度。

数组类和普通类不同,数组类没有对应的Class文件,所以数组类是直接被虚拟机创建的。HotSpot在初始化时就会创建好8个基本类型的一维数组对象TypeArrayKlass。之前在讲解HotSpot启动时讲到过,调用initializeJVM()方法初始化HotSpot,这个方法会最终调用到Universe::genesis()方法,在这个方法中初始化基本类型的一维数组对象TypeArrayKlass。例如初始化boolean类型的一维数组,调用语句如下:

_boolArrayKlassObj      = TypeArrayKlass::create_klass(T_BOOLEAN, sizeof(jboolean), CHECK);

其中_boolArrayKlassObj是声明在universe.cpp文件中的全局变量,如下:

Klass* Universe::_boolArrayKlassObj                 = NULL;

调用TypeArrayKlass::create_klass()方法创建TypeArrayKlass对象,具体就是调用TypeArrayKlass::create_klass()方法来完成,方法的实现如下:

TypeArrayKlass* TypeArrayKlass::allocate(ClassLoaderData* loader_data, BasicType type, Symbol* name, TRAPS) {
assert(TypeArrayKlass::header_size() <= InstanceKlass::header_size(),
"array klasses must be same size as InstanceKlass"); int x = TypeArrayKlass::header_size();
int size = ArrayKlass::static_size(x);
// 调用的构造函数在下面
return new (loader_data, size, THREAD) TypeArrayKlass(type, name);
}

非常类似于InstanceKlass等对象的创建,首先获取需要内存的大小size,然后通过重载new运算符完成对象内存分配后,调用TypeArrayKlass初始化一些属性,TypeArrayKlass的构造函数如下:

TypeArrayKlass::TypeArrayKlass(BasicType type, Symbol* name) : ArrayKlass(name) {
int lh = array_layout_helper(type);
set_layout_helper(lh);
assert(oop_is_array(), "sanity");
assert(oop_is_typeArray(), "sanity"); set_max_length(arrayOopDesc::max_array_length(type)); // 设置数组的最大长度
...
}

下面详细介绍一下对_layout_helper属性的设置。调用Klass::array_layout_helper()方法获取_layout_helper属性的值

jint Klass::array_layout_helper(BasicType etype) {
assert(etype >= T_BOOLEAN && etype <= T_OBJECT, "valid etype");
// Note that T_ARRAY is not allowed here.
int hsize = arrayOopDesc::base_offset_in_bytes(etype); // hsize表示数组对象头部大小
int esize = type2aelembytes(etype); // 对应类型存储所需要的字节数
bool isobj = (etype == T_OBJECT);
int tag = isobj ? _lh_array_tag_obj_value : _lh_array_tag_type_value;
int esz = exact_log2(esize);
int lh = array_layout_helper(tag, hsize, etype, esz); return lh;
}

关于_layout_helper在之前已经介绍过,由于T_BOOLEAN为基本类型,所以值为0xC0;hsize调用arrayOopDesc::base_offset_in_bytes()方法获取,值为16,后面在讲解arrayOopDesc时会介绍,数组对象其实是由对象头、对象字段数据和对齐填充组成,而这里获取的就是对象头的大小;esize表示对应类型存储所需要的字节数,对于T_BOOLEAN来说,只需要1个字节即可,所以esz为0。最后调用array_layout_helper()方法按照约定组合成一个int类型的数字即可。array_layout_helper()方法的实现如下:

 static jint array_layout_helper(jint tag, int hsize, BasicType etype, int log2_esize) {
return (tag << _lh_array_tag_shift) // 左移30位
| (hsize << _lh_header_size_shift) // 左移16位
| ((int)etype << _lh_element_type_shift) // 左移1位
| (log2_esize << _lh_log2_element_size_shift); // 左移0位
}

另外还有对_component_mirror属性的设置。对于一维基本类型的数组来说,这个值是java.lang.Class对象。Class对象使用oop对象来表示,调用java_lang_Class::create_basic_type_mirror()方法获取_component_mirror属性的值,通过java_lang_Class::create_mirror()方法完成属性的设置。例如获取boolean类型的属性值,调用语句如下:

void Universe::initialize_basic_type_mirrors(TRAPS) {
...
_bool_mirror = java_lang_Class::create_basic_type_mirror("boolean",T_BOOLEAN, CHECK);
...
}

方法create_basic_type_mirror()的实现如下:

oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) {
// This should be improved by adding a field at the Java level or by
// introducing a new VM klass (see comment in ClassFileParser)
oop java_class = InstanceMirrorKlass::cast(SystemDictionary::Class_klass())->allocate_instance(NULL, CHECK_0);
if (type != T_VOID) {
Klass* aklass = Universe::typeArrayKlassObj(type);
assert(aklass != NULL, "correct bootstrap");
set_array_klass(java_class, aklass); // 设置表示基本类型数组的TypeArrayKlass的
}
return java_class;
}

通过InstanceMirrorKlass对象(表示java.lang.Class类)来创建oop(表示java.lang.Class对象),所以_component_mirror最终设置的就是这个oop。引用类型组成的一维或多维数组的基本元素可以使用Klass对象来表示,如对于下面即将要介绍的Object[]来说,元素类型为Object,所以可以使用InstanceKlass来表示;基本类型组成的一维或多维数组的基本元素没有对应的Klass对象,所以只能使用Class对象来描述boolean、int等,这样就会与表示Class对象的InstanceMirrorKlass对象产生关系,相关属性最终的值如下所示。

TypeArrayKlass._component_mirror=InstanceMirrorKlass

InstanceMirrorKlass._array_klass=TypeArrayKlass

其它的属性设置很简单,这里不在介绍。

(2)ObjArrayKlass类

ObjArrayKlass是ArrayKlass的子类,用于表示数组元素是类或者数组

class ObjArrayKlass : public ArrayKlass {
...
private:
Klass* _element_klass; // The klass of the elements of this array type
Klass* _bottom_klass; // The one-dimensional type (InstanceKlass or TypeArrayKlass)
...
}

该类新增了2个属性,如下:

  • _element_klass:数组元素对应的Klass引用,如果是多维数组,对应数组元素的ObjArrayKlass的引用
  • _bottom_klass:一维数组的类型,可以是InstanceKlass或者TypeArrayKlass。一维基本类型数组为TypeArrayKlass,而二维基本类型数组就会使用ObjArrayKlass来表示,所以其_bottom_klass会是TypeArrayKlass。 

HotSpot在Universe::genesis()方法中创建Object数组,如下:

InstanceKlass* ik = InstanceKlass::cast(SystemDictionary::Object_klass());
_objectArrayKlassObj = ik->array_klass(1, CHECK); // 调用表示Object类的InstanceKlass类的array_klass()方法

调用array_klass()方法时传递的参数1表示创建一维数组。调用表示Object类的InstanceKlass对象的方法创建的,所以Object数组的创建要依赖于InstanceKlass对象(表示Object类)进行创建。

最终表示Object类的InstanceKlass与表示一维数组Object[]的ObjArrayKlass之间的相关属性如下:

ObjArrayKlass._element_klass=InstanceKlass
ObjArrayKlass._bottom_klass=InstanceKlass InstanceKlass._array_name="[Ljava/lang/Object;"
InstanceKlass._array_klasses=ObjArrayKlass

ObjArrayKlass中其它的属性设置也并不复杂,这里不在介绍。

相关文章的链接如下:

1、在Ubuntu 16.04上编译OpenJDK8的源代码

2、调试HotSpot源代码

3、HotSpot项目结构 

4、HotSpot的启动过程

5、HotSpot二分模型 (1)

6、HotSpot的类模型(2)

7、HotSpot的类模型(3)

关注公众号,有HotSpot源码剖析系列文章!

HotSpot的类模型(4)的更多相关文章

  1. HotSpot的类模型(3)

    上一篇 HotSpot的类模型(2) 介绍了类模型的基础类Klass的重要属性及方法,这一篇介绍一下InstanceKlass及InstanceKlass的子类. 2.InstanceKlass类 每 ...

  2. HotSpot的类模型(2)

    在前一篇文章 HotSpot的二分模型中已经讲过,HotSpot采用了OOP-Klass模型描述Java的类和对象.Klass模型采用Klass类及相关子类来表示具体的Java类,可以理解这些类为Ja ...

  3. HotSpot类模型之InstanceKlass

    上一篇 HotSpot源码分析之类模型 介绍了类模型的基础类Klass的重要属性及方法,这一篇介绍一下InstanceKlass及InstanceKlass的子类. 1.InstanceKlass类 ...

  4. HotSpot类模型之ArrayKlass

    上一篇分析了 HotSpot类模型之InstanceKlass ,这次主要分析表示java数组类型的C++类. 1.ArrayKlass类 ArrayKlass继承自Klass,是所有数组类的抽象基类 ...

  5. .NET使用DAO.NET实体类模型操作数据库

    一.新建项目 打开vs2017,新建一个项目,命名为orm1 二.新建数据库 打开 SqlServer数据库,新建数据库 orm1,并新建表 student . 三.新建 ADO.NET 实体数据模型 ...

  6. laravel5.8笔记五:基类控制器和基类模型

    建立基类的目的就是为了方便继承.比如:Admin模块访问,是否登陆.检测登陆可以写到基类里面 控制器基类 原始基类:app\Http\Controllers\Controller.php,我们下面要做 ...

  7. Paddle Graph Learning (PGL)图学习之图游走类模型[系列四]

    Paddle Graph Learning (PGL)图学习之图游走类模型[系列四] 更多详情参考:Paddle Graph Learning 图学习之图游走类模型[系列四] https://aist ...

  8. DL4NLP——词表示模型(一)表示学习;syntagmatic与paradigmatic两类模型;基于矩阵的LSA和GloVe

    本文简述了以下内容: 什么是词表示,什么是表示学习,什么是分布式表示 one-hot representation与distributed representation(分布式表示) 基于distri ...

  9. 自定义MVC框架之工具类-模型类

    截止目前已经改造了5个类: ubuntu:通过封装验证码类库一步步安装php的gd扩展 自定义MVC框架之工具类-分页类的封装 自定义MVC框架之工具类-文件上传类 自定义MVC框架之工具类-图像处理 ...

随机推荐

  1. 【asp.net core 系列】8 实战之 利用 EF Core 完成数据操作层的实现

    0. 前言 通过前两篇,我们创建了一个项目,并规定了一个基本的数据层访问接口.这一篇,我们将以EF Core为例演示一下数据层访问接口如何实现,以及实现中需要注意的地方. 1. 添加EF Core 先 ...

  2. 如何将H5一键部署到托管服务中

    随着各个大型App都推出了自己的小游戏平台,游戏也越来越受到开发者的关注.Cocos Creator是一个完整的游戏开发解决方案,包含了轻量高效的跨平台游戏引擎,以及能让你更快速开发游戏所需要的各种图 ...

  3. 如何使用 Shell 脚本来查看多个服务器的端口是否打开?

    我们在进行服务器配置的时候,经常要查看服务器的某个端口是否已经开放.如果服务器只有一两台的话,那很好办,只需要使用 nc 命令一个个查看即可. 但是,如果你的服务器是个集群,有很多台呢?那如果还一个个 ...

  4. fiddler修改请求参数

    1.打开fiddler ,点击界面左侧左侧底部 2.此图标为before request请求(修改请求参数时,设置这个,可以修改请求参数) 3..再次点击该按钮,将图标切换到下图after respo ...

  5. 增值税发票税控开票软件助手Excel、ERP、SAP导入开票接口进行批量开票操作手册

    写这遍文章的目的是方便以后个人使用,做个笔记记录. 首先我来说一下它是做什么用的,它的主要作用是把用户的开票数据,Excel数据.ERP 系统.SAP导入到增值税发票税控开票软件中,可用航信盘.百旺盘 ...

  6. 事务的特性ACID、隔离级别

    1.事务特性ACID 1.1 事务的四大特性 1.原子性(Atomicity) 事务包装的一组sql,要么都执行成功,要么都失败.这些操作是不可分割的. 2.一致性(Consistency) 数据库的 ...

  7. Beta冲刺--冲刺总结

    这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 Beta 冲刺 这个作业的目标 Beta冲刺--冲刺总结 作业正文 如下 其他参考文献 ... Beta冲刺 ...

  8. MyBatis一对多嵌套list返回结果集以及分页查询问题处理

    这两天在整理原有系统接口时,遇到后端的人员-角色-菜单的权限接口没有进行连表的关联查询操作,前端拿数据非常不方便,现在将接口相关sql进行修改并让前端可以一次性拿到想要的数据 原有的单表简单sql: ...

  9. 明文暴露___JS前台加密,java后台解密实现

    1.前台JS <script type="text/javascript"> $(function() { $("#btn").click(func ...

  10. 001_动力节点_SpringMVC4_SpringMVC简介

    1.视频的下载地址是 下载地址:百度云盘 链接:http://pan.baidu.com/s/1ge58XW3 密码:yd5jhttp://www.java1234.com/a/javaziliao/ ...