专注虚拟机与编译器研究

2020年11月19日

第2.1篇-HotSpot VM源码分析之C++对象的内存布局

摘要: HotSpot采用了OOP-Klass模型来描述Java类和对象。OOP(Ordinary Object Pointer)指的是普通对象指针,而Klass用来描述对象的具体类型。为了更好理解这个模型,首先要介绍一下C++的内存对象模型和虚函数。 这里只简单介绍一下,如果要深入了解C++对象模型,建议 阅读全文

posted @ 2020-11-19 08:15 鸠摩(马智) 阅读(1193) 评论(0) 推荐(0) 编辑

2020年11月18日

第1.4篇-HotSpot VM的启动过程(配视频进行源码分析)

摘要: 本文将详细介绍HotSpot的启动过程,启动过程涉及到的逻辑比较复杂,细节也比较多,为了让大家更快的了解这部分知识,我录制了对应的视频放到了B站上,大家可以参考。 第4节-HotSpot的启动过程 下面我们开始以文章的形式简单介绍一下启动过程。 HotSpot通常会通过JAVA_HOME目录下的bi 阅读全文

posted @ 2020-11-18 09:17 鸠摩(马智) 阅读(1714) 评论(2) 推荐(0) 编辑

2020年11月17日

第1.2篇-调试HotSpot VM源代码(配视频)

摘要: 本文将详细介绍在Ubuntu16.04 LTS上对OpenJDK8进行编译,为了方便大家快速搭建起OpenJDK8的调试开发环境,我还录制了对应的视频放到了B站上,大家可以参考。 视频地址:https://space.bilibili.com/27533329 下面我们开始环境的搭建过程。 之前的文 阅读全文

posted @ 2020-11-17 06:50 鸠摩(马智) 阅读(2097) 评论(0) 推荐(1) 编辑

2020年11月16日

第1.1篇-在Ubuntu 16.04上编译OpenJDK8的源代码(配视频)

摘要: 本文将详细介绍在Ubuntu16.04 LTS上对OpenJDK8进行编译,为了方便大家快速搭建起OpenJDK8的调试开发环境,我还录制了对应的视频放到了B站上,大家可以参考。 视频地址:https://space.bilibili.com/27533329 下面我们开始环境的搭建过程。 1、准备 阅读全文

posted @ 2020-11-16 07:32 鸠摩(马智) 阅读(1671) 评论(4) 推荐(0) 编辑

2020年8月21日

转发表

摘要: TemplateInterpreter::initialize()方法实现如下: 源代码位置:/src/share/vm/interpreter/templateInterpreter.cpp void TemplateInterpreter::initialize() { if (_code != 阅读全文

posted @ 2020-08-21 16:33 鸠摩(马智) 阅读(519) 评论(0) 推荐(0) 编辑

2020年8月19日

模板表

摘要: Java的模板解析执行需要模板表与转发表的支持,而这2个表中的数据在HotSpot虚拟机启动时就会初始化。这一篇首先介绍模板表。 在启动虚拟机阶段会调用init_globals()方法初始化全局模块,在这个方法中通过调用interpreter_init()方法初始化模板解释器,调用栈如下: Temp 阅读全文

posted @ 2020-08-19 06:49 鸠摩(马智) 阅读(632) 评论(0) 推荐(0) 编辑

2020年8月18日

虚拟机执行模式

摘要: 在HotSpot里面,代码执行有两种模式: 直接解释指令:这使用的是HotSpot的解释引擎,它采用模板解释,将每一条指令直接翻译成本地代码,而后由硬件直接执行; 编译执行:是指,将代码直接翻译成本地代码执行,这就是耳熟能详的JIT编译器,更加准确的说是HotSpot Compiler; HotSp 阅读全文

posted @ 2020-08-18 16:22 鸠摩(马智) 阅读(699) 评论(0) 推荐(0) 编辑

dispatch_next()方法的实现

摘要: 之前的文章介绍到,在generate_normal_entry()函数中会调用generate_fixed_frame()函数为Java方法的执行生成对应的栈帧,接下来还会调用dispatch_next()函数执行Java方法的字节码。generate_normal_entry()函数中调用的dis 阅读全文

posted @ 2020-08-18 10:54 鸠摩(马智) 阅读(622) 评论(0) 推荐(0) 编辑

generate_fixed_frame()方法生成Java方法栈帧

摘要: 在从generate_normal_entry()函数调用generate_fixed_frame()函数时的栈与寄存器的状态如下: 栈的状态如下图所示。 各个寄存器的状态如下所示。 rax: return address // %rax寄存器中存储的是返回地址r rbx: Method* // 要 阅读全文

posted @ 2020-08-18 09:35 鸠摩(马智) 阅读(675) 评论(0) 推荐(0) 编辑

JVM的方法执行引擎-entry point栈帧

摘要: 接着上一篇去讲,回到JavaCalls::call_helper()中: address entry_point = method->from_interpreted_entry(); entry_point是从当前要执行的Java方法中获取的,定义如下: 源代码位置:/openjdk/hotspo 阅读全文

posted @ 2020-08-18 08:24 鸠摩(马智) 阅读(1184) 评论(0) 推荐(0) 编辑

2020年8月17日

CallStub栈帧

摘要: 之前多次提到接触到调用JavaCalls::call()函数来执行Java方法,如: (1)Java主类装载时,调用JavaCalls::call()方法执行的Java方法checkAndLoadMain()方法; (2)类的初始化过程中,调用JavaCalls::call()方法执行的Java方法 阅读全文

posted @ 2020-08-17 10:36 鸠摩(马智) 阅读(1040) 评论(0) 推荐(0) 编辑

2020年8月16日

HotSpot的垃圾回收器

摘要: 如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。这里讨论的收集器基于JDK 1.7 Update 14之后的 HotSpot 虚拟机,这个虚拟机包含的所有收集器如下图所示 上图展示了 7 种作用于不同分代的收集器,如果两个收集器之间存在连线,就说明它们可以搭配使用。虚拟机所处 阅读全文

posted @ 2020-08-16 10:33 鸠摩(马智) 阅读(685) 评论(0) 推荐(0) 编辑

HotSpot的垃圾回收算法

摘要: 这系列文章只简单介绍一下HotSpot垃圾回收中涉及到的算法及相关的垃圾回收器,并不进行源代码分析,后面会开一个系列对HotSpot的垃圾回收以及内存管理进行源代码解读。 涉及到的垃圾回收算法一共有 4 种: 标记-清除算法 复制算法 标记整理算法 分代收集算法 标记-清除算法 最基础的收集算法是“ 阅读全文

posted @ 2020-08-16 10:32 鸠摩(马智) 阅读(649) 评论(0) 推荐(0) 编辑

Java引用类型之最终引用

摘要: FinalReference类只有一个子类Finalizer,并且Finalizer由关键字final修饰,所以无法继承扩展。类的定义如下: class FinalReference<T> extends Reference<T> { public FinalReference(T referent 阅读全文

posted @ 2020-08-16 10:22 鸠摩(马智) 阅读(398) 评论(0) 推荐(0) 编辑

Java引用类型之弱引用与幻像引用

摘要: 这一篇将介绍弱引用和幻像引用。 1、WeakReference WeakReference也就是弱引用,弱引用和软引用类似,它是用来描述"非必须"的对象的,它的强度比软引用要更弱一些。被弱引用关联的对象只能生存到下一次垃圾收集发生之前,简言之就是:一旦发生GC必定回收被弱引用关联的对象,不管当前的内 阅读全文

posted @ 2020-08-16 10:20 鸠摩(马智) 阅读(387) 评论(0) 推荐(0) 编辑

Java引用类型之软引用(2)

摘要: 下面接着上一篇介绍第2阶段和第3阶段的处理逻辑。 2、process_phase2() 第2个阶段移除所有的referent还存活的Reference,也就是从refs_list中移除Reference。process_phase2()方法的实现如下: // Phase2: remove all t 阅读全文

posted @ 2020-08-16 09:37 鸠摩(马智) 阅读(303) 评论(0) 推荐(0) 编辑

Java引用类型之软引用(1)

摘要: Java使用SoftReference来表示软引用,软引用是用来描述一些“还有用但是非必须”的对象。对于软引用关联着的对象,在JVM应用即将发生内存溢出异常之前,将会把这些软引用关联的对象列进去回收对象范围之中进行第二次回收。如果这次回收之后还是没有足够的内存,才会抛出内存溢出异常。简单来说就是: 阅读全文

posted @ 2020-08-16 09:29 鸠摩(马智) 阅读(603) 评论(0) 推荐(0) 编辑

2020年8月15日

Java引用类型

摘要: Java中一共有4种引用类型(其实还有一些其他的引用类型比如FinalReference):强引用、软引用、弱引用、虚引用。其中强引用就是如下的情况: Object a=new Object(); obj持有的Object对象的引用就是强引用,在Java中并没有对应的Reference类。 本篇文章 阅读全文

posted @ 2020-08-15 08:46 鸠摩(马智) 阅读(625) 评论(0) 推荐(0) 编辑

对象的创建

摘要: Java对象创建的流程大概如下: 检查对象所属类是否已经被加载解析; 为对象分配内存空间; 将分配给对象的内存初始化为零值; 执行对象的<init>方法进行初始化。 举个例子如下: public class Test { public static void main(String[] args) 阅读全文

posted @ 2020-08-15 08:45 鸠摩(马智) 阅读(894) 评论(0) 推荐(0) 编辑

2020年8月13日

第7.6篇-类的初始化

摘要: 对类进行初始化时,通常会调用如下方法: void InstanceKlass::initialize(TRAPS) { if (this->should_be_initialized()) { HandleMark hm(THREAD); instanceKlassHandle this_oop(T 阅读全文

posted @ 2020-08-13 15:49 鸠摩(马智) 阅读(914) 评论(0) 推荐(0) 编辑

初始化itable

摘要: 在InstanceKlass::link_class_impl()方法中完成方法连接后会继续初始化vtable与itable,之前已经介绍过vtable与itable,并且在类解析过程中已经完成了大小的计算并且也为相关信息的存储开辟了对应的内存空间,也就是在InstanceKlass本身需要占用的内 阅读全文

posted @ 2020-08-13 12:11 鸠摩(马智) 阅读(865) 评论(0) 推荐(0) 编辑

初始化vtable

摘要: 在InstanceKlass::link_class_impl()方法中完成方法连接后会继续初始化vtable与itable,之前已经介绍过vtable与itable,并且在类解析过程中已经完成了大小的计算并且也为相关信息的存储开辟了对应的内存空间,也就是在InstanceKlass本身需要占用的内 阅读全文

posted @ 2020-08-13 09:57 鸠摩(马智) 阅读(730) 评论(0) 推荐(0) 编辑

2020年8月12日

第7.5篇-方法的连接

摘要: 方法连接做的最主要的事就是为方法的执行设置解释入口和编译入口。在InstanceKlass::link_class_impl()方法中对字节码验证完成后会调用InstanceKlass::link_methods()方法,如下: // Now relocate and link method ent 阅读全文

posted @ 2020-08-12 09:40 鸠摩(马智) 阅读(531) 评论(0) 推荐(0) 编辑

第7.4篇-类的连接之重写(2)

摘要: 接着上一篇继续分析Rewriter::Rewriter()构造函数中完成的逻辑。在构造函数中会调用make_constant_pool_cache()函数,不过在先介绍这个函数之前,需要介绍一下ConstantPoolCache与ConstantPoolCacheEntry。这两个类都定义在cpCa 阅读全文

posted @ 2020-08-12 09:26 鸠摩(马智) 阅读(746) 评论(0) 推荐(0) 编辑

2020年8月11日

第7.3篇-类的连接之重写(1)

摘要: 调用InstanceKlass类的rewrite_class()函数重写字节码,实现如下: // Rewrite the byte codes of all of the methods of a class. // The rewriter must be called exactly once. 阅读全文

posted @ 2020-08-11 11:35 鸠摩(马智) 阅读(625) 评论(0) 推荐(0) 编辑

第7.2篇-类的连接之验证

摘要: 在介绍字节码连接之前,有必要介绍一下字节码验证。HotSpot虚拟机其实会遵守《Java虚拟机规范》,对Class文件中包含的信息进行合法性验证,以保证虚拟机的安全。从整体上来看,验证阶段大致上会进行如下4方面的验证: 文件格式验证:包括魔数,版本号等; 元数据验证:对程序进行语义分析,如是否有父类 阅读全文

posted @ 2020-08-11 09:12 鸠摩(马智) 阅读(529) 评论(0) 推荐(0) 编辑

第7.1篇-类的连接

摘要: 在类的连接之前要保证对类进行了解析,例如初始化一个类时会调用initialize_class()方法,实现如下: static void initialize_class(Symbol* class_name, TRAPS) { Klass* klass = SystemDictionary::re 阅读全文

posted @ 2020-08-11 08:39 鸠摩(马智) 阅读(849) 评论(0) 推荐(0) 编辑

2020年8月10日

第5.6篇-字段解析之字段注入

摘要: 之前已经介绍过字段解析,不过由于我的疏忽,丢了一部分不得不介绍的内容,那就是字段注入。举个例子如下: package jvmTest; import java.lang.management.ManagementFactory; import java.lang.management.Runtime 阅读全文

posted @ 2020-08-10 16:29 鸠摩(马智) 阅读(869) 评论(0) 推荐(0) 编辑

解析Class文件之创建InstanceKlass对象

摘要: ClassFileParser::parseClassFile()方法会将解析Class文件的大部分结果保存到instanceKlass对象中。创建instanceKlass对象的代码如下: int total_oop_map_size2 = InstanceKlass::nonstatic_oop 阅读全文

posted @ 2020-08-10 16:28 鸠摩(马智) 阅读(3054) 评论(0) 推荐(2) 编辑

2020年8月9日

第6.5篇-计算itable的大小

摘要: 在ClassFileParser::parseClassFile()函数中计算vtable和itable所需要的大小,之前已经介绍过vtable大小的计算,这一篇将详细介绍itable大小的计算过程。调用语句如下: // Size of Java itable (in words) if( acce 阅读全文

posted @ 2020-08-09 15:29 鸠摩(马智) 阅读(634) 评论(0) 推荐(0) 编辑

第6.4篇-计算vtable的大小

摘要: 在ClassFileParser::parseClassFile()函数中会计算vtable和itable所需要的大小,因为vtable和itable是内嵌在Klass中的,parseClassFile()函数解析完Class文件后会创建instanceKlass来保存相关的信息,在创建instan 阅读全文

posted @ 2020-08-09 15:28 鸠摩(马智) 阅读(724) 评论(0) 推荐(0) 编辑

2020年8月8日

第6.3篇-klassVtable与klassItable类的介绍

摘要: klassVtable与klassItable类用来实现Java方法的多态,也可以叫动态绑定,是指在应用执行期间通过判断接受对象的实际类型,根据实际类型调用对应的方法。C++为了实现多态,在对象中嵌入了虚函数表vtable,通过虚函数表来实现运行期的方法分派,这在之前介绍HotSpot的二分模型时简 阅读全文

posted @ 2020-08-08 10:17 鸠摩(马智) 阅读(1372) 评论(0) 推荐(0) 编辑

第6.2篇-方法解析

摘要: 在ClassFileParser::parseClassFile()函数中解析完字段并完成每个字段的布局后,会继续对方法进行解析,相关的处理语句如下: bool has_final_method = false; AccessFlags promoted_flags; promoted_flags. 阅读全文

posted @ 2020-08-08 09:35 鸠摩(马智) 阅读(567) 评论(0) 推荐(0) 编辑

第6.1篇-方法解析之Method与ConstMethod介绍

摘要: Method中的一个重要字段为_intrinsic_id,为了追求极致的性能,将这些方法叫固有方法(Intrinsic Method)。所有的固有方法都能在classfile/vmSymbols.hpp中找到,一个绝佳的例子是java.lang.Math。对于Math.sqrt(),用Java或者J 阅读全文

posted @ 2020-08-08 07:39 鸠摩(马智) 阅读(1161) 评论(0) 推荐(0) 编辑

第5.5篇-使用HSDB查看类变量的内存布局

摘要: 如下的实例来自Hotspot 垃圾回收之oop_iterate(一) 源码解析,我做了一些微小的改动。 查看如下实例的内存布局: package com.test; public class Parent { private Integer a = 1; protected long b = 2; 阅读全文

posted @ 2020-08-08 07:11 鸠摩(马智) 阅读(756) 评论(0) 推荐(0) 编辑

2020年8月1日

第5.4篇-字段解析之OopMapBlock

摘要: OopMapBlock是一个简单的内嵌在Klass里面的数据结构,用来描述oop中包含的引用类型属性,即该oop所引用的其他oop在oop中的内存分布,然后就可以根据当前oop的地址找到所有引用的其他oop了,其定义如下: 源代码位置:oops/instanceKlass.hpp // ValueO 阅读全文

posted @ 2020-08-01 08:03 鸠摩(马智) 阅读(998) 评论(0) 推荐(0) 编辑

第5.3篇-字段解析

摘要: 对象的定义顺序和布局顺序是不一样的。我们在写代码的时候不用关心内存对齐问题,但是如果内存按照源代码定义顺序进行布局的话,由于cpu读取内存时是按寄存器(64位)大小单位载入的,如果载入的数据横跨两个64位,要操作该数据的话至少需要两次读取,加上组合移位,会产生效率问题,甚至会引发异常。比如在一些AR 阅读全文

posted @ 2020-08-01 07:20 鸠摩(马智) 阅读(902) 评论(0) 推荐(0) 编辑

2020年7月31日

第5.2篇-字段解析之伪共享

摘要: 好文章: https://www.cnblogs.com/tong-yuan/p/FalseSharing.html 缓存系统中是以缓存行(cache line)为单位存储的。缓存行是2的整数幂个连续字节,一般为32-256个字节。最常见的缓存行大小是64个字节。当多线程修改互相独立的变量时,如果这 阅读全文

posted @ 2020-07-31 15:28 鸠摩(马智) 阅读(546) 评论(0) 推荐(0) 编辑

第5.1篇-字段解析

摘要: 在ClassfileParser::parseClassFile()函数中,解析完常量池、父类和接口后,接着会调用parser_fields()函数解析字段信息。调用语句如下: u2 java_fields_count = 0; // Fields (offsets are filled in la 阅读全文

posted @ 2020-07-31 14:55 鸠摩(马智) 阅读(672) 评论(0) 推荐(0) 编辑

第4.5篇-常量池解析(2)

摘要: 在parse_constant_pool()方法中调用parse_constant_pool_entries()方法对常量池中的各个项进行解析,方法的实现如下: void ClassFileParser::parse_constant_pool_entries(int length, TRAPS) 阅读全文

posted @ 2020-07-31 10:30 鸠摩(马智) 阅读(941) 评论(0) 推荐(0) 编辑

导航