HotSpot的类模型(4)
我们继续接着上一篇 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的源代码
关注公众号,有HotSpot源码剖析系列文章!

HotSpot的类模型(4)的更多相关文章
- HotSpot的类模型(3)
上一篇 HotSpot的类模型(2) 介绍了类模型的基础类Klass的重要属性及方法,这一篇介绍一下InstanceKlass及InstanceKlass的子类. 2.InstanceKlass类 每 ...
- HotSpot的类模型(2)
在前一篇文章 HotSpot的二分模型中已经讲过,HotSpot采用了OOP-Klass模型描述Java的类和对象.Klass模型采用Klass类及相关子类来表示具体的Java类,可以理解这些类为Ja ...
- HotSpot类模型之InstanceKlass
上一篇 HotSpot源码分析之类模型 介绍了类模型的基础类Klass的重要属性及方法,这一篇介绍一下InstanceKlass及InstanceKlass的子类. 1.InstanceKlass类 ...
- HotSpot类模型之ArrayKlass
上一篇分析了 HotSpot类模型之InstanceKlass ,这次主要分析表示java数组类型的C++类. 1.ArrayKlass类 ArrayKlass继承自Klass,是所有数组类的抽象基类 ...
- .NET使用DAO.NET实体类模型操作数据库
一.新建项目 打开vs2017,新建一个项目,命名为orm1 二.新建数据库 打开 SqlServer数据库,新建数据库 orm1,并新建表 student . 三.新建 ADO.NET 实体数据模型 ...
- laravel5.8笔记五:基类控制器和基类模型
建立基类的目的就是为了方便继承.比如:Admin模块访问,是否登陆.检测登陆可以写到基类里面 控制器基类 原始基类:app\Http\Controllers\Controller.php,我们下面要做 ...
- Paddle Graph Learning (PGL)图学习之图游走类模型[系列四]
Paddle Graph Learning (PGL)图学习之图游走类模型[系列四] 更多详情参考:Paddle Graph Learning 图学习之图游走类模型[系列四] https://aist ...
- DL4NLP——词表示模型(一)表示学习;syntagmatic与paradigmatic两类模型;基于矩阵的LSA和GloVe
本文简述了以下内容: 什么是词表示,什么是表示学习,什么是分布式表示 one-hot representation与distributed representation(分布式表示) 基于distri ...
- 自定义MVC框架之工具类-模型类
截止目前已经改造了5个类: ubuntu:通过封装验证码类库一步步安装php的gd扩展 自定义MVC框架之工具类-分页类的封装 自定义MVC框架之工具类-文件上传类 自定义MVC框架之工具类-图像处理 ...
随机推荐
- HTML的简介和历史发展过程
HTML的简介和历史发展过程 前言 这次写一篇对于HTML以及CSS的简介,平常我们大家都知道的编程语言有很多种,比如Java.C++.Python等等,每种编程语言都有其独具的特色,不论是语法格式还 ...
- @atcoder - AGC003F@ Fraction of Fractal
目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一个 H*W 黑白格图,保证黑格四连通. 定义分形如下:0 ...
- GridView绑定数据与隐藏指定控件(模板列)
1.1. GridView绑定数据 1) 可以配置SqlDataSource数据源,修改select语句生成框架(不想手动绑定) 2) 删除DataSourceID属性和 ...
- git 的使用:
git 的官方网址是: https://git-scm.com/downloads github 的官方网址: https://github.com/ git 的原理图: git 和 github ...
- SpringBoot中注入ApplicationContext对象的三种方式
[本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究.若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!] 在项目中,我们可 ...
- IntelliJ IDEA 2018.3.6 安装、激活 JRebel
在 IntelliJ IDEA 2018.3.6 中安装## JRebel 1.代开 IDEA 开发工具,然后用快捷键 Ctrl+Alt+S 打开设置并搜索 jrebel 插件 2.安装 jrebel ...
- Python 简明教程 --- 16,Python 高阶函数
微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 对于那些快速算法,我们总是可以拿一些速度差不多但是更容易理解的算法来替代它们. -- Douglas ...
- WARN deploy.SparkSubmit$$anon$2: Failed to load org.apache.spark.examples.sql.streaming.StructuredNetworkWordCount.
前言 今天运行Spark Structured Streaming官网的如下 ./bin/run-example org.apache.spark.examples.sql.streaming.Str ...
- 一个比CBitmap更优秀的类 -- CImage类
Visual C++的CBitmap类的功能是比较弱的,它只能显示出在资源中的图标.位图.光标以及图元文件的内容,而不像VB中的Image控件可以显示出绝大多数的外部图像文件(BMP.GIF.JPEG ...
- React-Native WebView使用本地js,css渲染html
前言 最近在使用React-Native开发一个App,遇见一个问题,Webview组件根据url来加载页面,但是这样导致的一个问题页面加载的时间有点长,我想优化一下,因为页面只要是一些内容展示,我想 ...