专注虚拟机与编译器研究

2023年10月29日

详述Java内存屏障,透彻理解volatile

摘要: 一般来说内存屏障分为两层:编译器屏障和CPU屏障,前者只在编译期生效,目的是防止编译器生成乱序的内存访问指令;后者通过插入或修改特定的CPU指令,在运行时防止内存访问指令乱序执行。 下面简单说一下这两种屏障。 1、编译器屏障 编译器屏障如下: asm volatile("": : :"memory" 阅读全文

posted @ 2023-10-29 09:23 鸠摩(马智) 阅读(758) 评论(0) 推荐(1) 编辑

2023年10月26日

关于CAS等原子操作,说点别人没说的

摘要: 说点原子操作CAS别人没有介绍过的知识点。 阅读全文

posted @ 2023-10-26 08:44 鸠摩(马智) 阅读(493) 评论(0) 推荐(0) 编辑

2023年10月18日

手写商用Java虚拟机HotSpot,疯狂磨练技术中

摘要: 在当前Java行业激烈竞争的形式下,唯有掌握技术,心中才能不慌。在多年前,我就开始苦深度钻研Java底层实现,将HotSpot虚拟机的各种实现看了个遍,但是眼看百遍也不如手过一遍,所以我打算把HotSpot虚拟机的精华实现部分用手敲出来,这个过程注定不会轻松,但主要是不能心急,心态一定要好,每天坚持 阅读全文

posted @ 2023-10-18 10:32 鸠摩(马智) 阅读(1297) 评论(5) 推荐(6) 编辑

2023年10月9日

C++一种巧妙的内存管理方式

摘要: 在HotSpot VM中定义了一个Relocation类及相关的子类,可以通过这些类操作不同的重定位数据,如在CodeCache中读写这些数据。这些类需要的内存很小,但是不同的类需要的内存大小又不一样,所以做了如下的设计: #include <cstdlib> #include "iostream" 阅读全文

posted @ 2023-10-09 08:20 鸠摩(马智) 阅读(325) 评论(0) 推荐(0) 编辑

2023年10月8日

C++的模板类在HotSpot VM中的应用

摘要: 模板是c++的一种特性,允许函数或者类通过泛型(generic types)的形式表现或者运行。模板可以使得函数或类在对应不同的类型(types)的时候正常工作,而无需为每一种类型分别写一份代码。 在HotSpot VM中定义了一些模板类,有了这些模板类,我们就可以和Java一样进行泛型编程。Hot 阅读全文

posted @ 2023-10-08 08:36 鸠摩(马智) 阅读(245) 评论(0) 推荐(2) 编辑

2023年9月30日

C++的extern关键字在HotSpot VM中的重要应用

摘要: extern关键字有两个用处: (1)extern在C/C++语言中表示函数和全局变量作用范围(可见性)的关键字,这个关键字会告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。 (2)在C++中引用C语言中的函数和变量,在包含C语言头文件时,需要使用extern "C"来处理。 1、ext 阅读全文

posted @ 2023-09-30 10:08 鸠摩(马智) 阅读(272) 评论(0) 推荐(2) 编辑

2023年9月25日

C++的动态分派在HotSpot VM中的重要应用

摘要: 众所周知,多态是面向对象编程语言的重要特性,它允许基类的指针或引用指向派生类的对象,而在具体访问时实现方法的动态绑定。C++ 和 Java 作为当前最为流行的两种面向对象编程语言,其内部对于多态的支持对于单继承的实现非常类似。 首先来体现一下C++的动态分派,如下: class Base1{ pub 阅读全文

posted @ 2023-09-25 07:59 鸠摩(马智) 阅读(268) 评论(0) 推荐(0) 编辑

2023年9月23日

C++指针和地址偏移在HotSpot VM中的应用

摘要: 在前面我们介绍过new运算符,这个操作实际上上包含了如下3个步骤: 调用operator new的标准库函数。此函数会分配一块内存空间以便函存储相应类型的实例; 调用相应类的构造函数; 返回一个指向该对象的指针。 在第一步中,其实我们可以自己写个operator new函数对标准库函数进行重载,通常 阅读全文

posted @ 2023-09-23 09:51 鸠摩(马智) 阅读(279) 评论(0) 推荐(0) 编辑

2023年9月22日

C++ 重载运算符在HotSpot VM中的应用

摘要: C++支持运算符重载,对于Java开发者来说,这个可能比较陌生一些,因为Java不支持运算符重载。运算符重载本质上来说就是函数重载。下面介绍一下HotSpot VM中的运算符重载。 1、内存分配与释放 在C++中可以通过new运算符创建一个C++的类实例,这个操作实际上上包含了如下3个步骤: 调用o 阅读全文

posted @ 2023-09-22 11:19 鸠摩(马智) 阅读(275) 评论(0) 推荐(2) 编辑

2023年9月21日

C++ RAII在HotSpot VM中的重要应用

摘要: 在HotSpot VM中,RAII对内存资源的管理和释放、明确定义范围锁及记录重要信息等方面起到了非常重要的作用。 阅读全文

posted @ 2023-09-21 19:49 鸠摩(马智) 阅读(340) 评论(0) 推荐(0) 编辑

2023年9月19日

JavaAgent寄生在目标进程中引起的ClassNotFoundException

摘要: 今天有解决方案部的小伙伴反映,我公司XWind产品在分析客户应用程序的潜在性能问题时,总是显现诊断任务异常,为了定位问题的根因,我们马上要求解决方案部的小伙伴提供XWind相关的日志,从日志中找到了如下报错信息: 可以看到Java经典的动态加载类错误,org.apache.naming.java.j 阅读全文

posted @ 2023-09-19 16:16 鸠摩(马智) 阅读(382) 评论(0) 推荐(1) 编辑

2023年9月18日

如何随心所欲调试HotSpot VM源代码?(改造为CMakeLists项目)

摘要: 常有小伙伴问我是怎么调试HotSpot VM源代码的,我之前通过视频和文章介绍过一种大家都用的调试方法,如下: 文章地址:第1.2篇-调试HotSpot VM源代码(配视频) 视频地址:https://space.bilibili.com/27533329 网上所有的文章都介绍的是这种方式,先将Ho 阅读全文

posted @ 2023-09-18 08:17 鸠摩(马智) 阅读(526) 评论(1) 推荐(0) 编辑

2022年2月16日

第63篇-解释器与编译器适配(二)

摘要: 这一篇详细介绍相关适配器的代码片段。 1、解释执行切换到编译执行的例程 调用SharedRuntime::gen_i2c_adapter()函数生成解释执行切换到编译执行的例程,如下: 0x00007fe462791120: mov (%rsp),%rax 0x00007fe462791124: m 阅读全文

posted @ 2022-02-16 08:49 鸠摩(马智) 阅读(500) 评论(0) 推荐(1) 编辑

2022年2月11日

第62篇-解释器与编译器适配(一)

摘要: 对栈上替换的nmethod而言,执行栈上替换就相当于安装,因为栈上替换的nmethod都是方法内部的调用,所以实现相对简单点。对非栈上替换的nmethod而言,其安装稍微复杂点,需要考虑从Java代码和本地代码中调用nmethod安装完成的方法的情形,HotSpot VM的实现是通过一个在字节码解释 阅读全文

posted @ 2022-02-11 08:38 鸠摩(马智) 阅读(585) 评论(0) 推荐(2) 编辑

2022年2月10日

第61篇-安装与卸载编译方法和OSR

摘要: 如果方法或OSR完成编译后,还需要安装到对应的位置才能执行。 可以看一下Compilation::compile_method()函数,最重要的实现代码如下: // compile method int frame_size = compile_java_method(); // ... if (I 阅读全文

posted @ 2022-02-10 09:01 鸠摩(马智) 阅读(348) 评论(0) 推荐(0) 编辑

2022年1月23日

第60篇-获取编译任务

摘要: 在前面介绍过OSR或方法编译,如果已经决定要编译,都会调用SimpleThresholdPolicy::compile()函数进行编译。调用的相关函数如下: 1、提交编译任务 在SimpleThresholdPolicy::compile()函数中会调用SimpleThresholdPolicy:: 阅读全文

posted @ 2022-01-23 10:46 鸠摩(马智) 阅读(386) 评论(0) 推荐(0) 编辑

2022年1月22日

第59篇-编译策略

摘要: 在执行OSR或方法编译时,调用AdvancedThresholdPolicy::common()函数决定编译策略,这样才能在SimpleThresholdPolicy::submit_compile()函数提交编译任务。common()函数的实现如下: CompLevel AdvancedThres 阅读全文

posted @ 2022-01-22 08:22 鸠摩(马智) 阅读(392) 评论(0) 推荐(0) 编辑

2022年1月21日

第58篇-触发编译

摘要: 在之前介绍方法调用计数和回边计数时介绍过,当计数值超过阈值时会调用InterpreterRuntime::frequency_counter_overflow()函数对方法或块进行编译。此函数会进一步调用到CompilationPolicy::event()函数,在此函数中会根据当前的编译模式选择合 阅读全文

posted @ 2022-01-21 06:29 鸠摩(马智) 阅读(370) 评论(0) 推荐(0) 编辑

2022年1月20日

第57篇-profile实例

摘要: 之前已经介绍过回边计数和ProfileData与Layout,下面举个具体的例子看下MethodData是怎么利用ProfileData等记录详细的运行时信息的。实例如下: package com.test; import java.util.LinkedList; public class Com 阅读全文

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

2022年1月19日

第56篇-ProfileData与DataLayout

摘要: 某些指令需要创建某些实例,如下: 指令 对应的DataLayout._struct._tag值 _checkcast、_instanceof、_aastore receiver_type_data_tag bit_data_tag _invokespecial、_invokestatic call_ 阅读全文

posted @ 2022-01-19 08:43 鸠摩(马智) 阅读(385) 评论(0) 推荐(0) 编辑

2022年1月17日

第55篇-回边计数

摘要: 在前面介绍控制转移指令时只简单介绍了相关字节码解释执行的主要逻辑,没有介绍过统计相关的逻辑。对于控制转移指令来说,通常会调用TemplateTable::branch(bool is_jsr, bool is_wide)函数生成相关的汇编代码,这些汇编代码会含有统计的逻辑,这一篇将详细介绍。 控制转 阅读全文

posted @ 2022-01-17 08:46 鸠摩(马智) 阅读(446) 评论(0) 推荐(1) 编辑

2022年1月14日

第54篇-方法调用计数

摘要: 前一篇介绍了编译策略,编译策略依赖于性能计数,所以HotSpot VM中有许多性能统计相关的代码,如统计方法调用次数的代码,统计回边的次数,这就是方法调用计数器(Invocation Counter )和回边计数器(Back Edge Counter )。有了这些统计信息,HotSpot VM就会判 阅读全文

posted @ 2022-01-14 08:56 鸠摩(马智) 阅读(650) 评论(0) 推荐(0) 编辑

2022年1月13日

第53篇-编译线程的初始化

摘要: 即时编译(Just In Time,JIT)的运行模式有两种:client模式(C1编译器)和server模式(C2编译器)。这两种模式采用的编译器是不一样的,client模式采用的是代号为C1的轻量级编译器,特点是启动快,但是编译不够彻底;而server模式采用的是代号为C2的编译器,特点是启动比 阅读全文

posted @ 2022-01-13 09:21 鸠摩(马智) 阅读(722) 评论(1) 推荐(0) 编辑

2022年1月12日

第52篇-即时编译器

摘要: 一般来说,Java代码会先被HotSpot VM解释执行,之后将统计出的热点代码通过即时编译器C1、C2或Graal编译成机器码,直接运行在底层硬件之上。解释器在之前的文章中已经介绍了不少,但是编译器还没有介绍,关于Java涉及到的编译器如下图所示。 前端编译器就是将遵循Java语言规范的Java源 阅读全文

posted @ 2022-01-12 08:23 鸠摩(马智) 阅读(777) 评论(0) 推荐(1) 编辑

2022年1月11日

第51篇-SharedRuntime::generate_native_wrapper()生成编译入口

摘要: 当某个native方法被调用时,一开始它会从解释入口进入,也就是我之前介绍的、由InterpreterGenerator::generate_native_entry()函数生成的入口例程。在这个例程中,其实还有一些统计的相关代码,但是当时为了专注研究解释执行的主要流程,为虚拟机增加了-XX:-Pr 阅读全文

posted @ 2022-01-11 08:54 鸠摩(马智) 阅读(411) 评论(0) 推荐(0) 编辑

2022年1月7日

第50篇-调用约定(2)

摘要: 前面已经介绍了解释执行的Java方法、编译执行的Java方法和native方法的调用约定。这一篇我们看一下HotSpot VM中辅助实现调用约定的相关函数。 1、SharedRuntime::java_calling_convention()函数 当需要编译执行Java方法时,会调用SharedRu 阅读全文

posted @ 2022-01-07 09:43 鸠摩(马智) 阅读(330) 评论(0) 推荐(0) 编辑

2021年12月31日

第49篇-调用约定(1)

摘要: JVM字节码使用了一些专业术语,当谈到调用点时,它指的是某个方法(调用者)内的一个位置,在那里另外一个方法(被调用者)被调用了,不仅如此,在非静态方法调用的情况下,我们总是将方法解析到某个对象上。这个对象就是所谓的接收者对象(receiver object),其运行时类型被称为接收者类型(recei 阅读全文

posted @ 2021-12-31 09:46 鸠摩(马智) 阅读(458) 评论(0) 推荐(0) 编辑

2021年12月30日

第48篇-native方法调用解释执行的Java方法

摘要: 举一个native方法调用解释执行的Java方法的实例,如下: public class TestJNI { static { System.load("/media/mazhi/sourcecode/workspace/projectjava/projectjava01/src/main/java 阅读全文

posted @ 2021-12-30 09:09 鸠摩(马智) 阅读(574) 评论(0) 推荐(0) 编辑

2021年12月29日

第47篇-解释执行的Java方法调用native方法小实例

摘要: 举个小实例,如下: public class TestJNI { static { // 程序在加载时,自动加载libdiaoyong.so库 System.loadLibrary("diaoyong"); } public static native int get(); public stati 阅读全文

posted @ 2021-12-29 14:37 鸠摩(马智) 阅读(643) 评论(0) 推荐(0) 编辑

2021年12月17日

第46篇-signature_handler与result_handler

摘要: 在之前介绍为native方法设置解释执行的入口时介绍过,当Method::native_function为空时会调用InterpreterRuntime::prepare_native_call()函数,这个函数不但会查找本地函数,而且还会确保Method::signature_handler也完成 阅读全文

posted @ 2021-12-17 09:19 鸠摩(马智) 阅读(352) 评论(0) 推荐(3) 编辑

2021年12月16日

第45篇-查找native方法的本地实现函数native_function

摘要: 在之前介绍为native方法设置解释执行的入口时讲到过Method实例的内存布局,如下: 对于第1个slot来说,如果是native方法,其对应的本地函数的实现会放到Method实例的native_function这个slot中,将本地函数放到这个slot就是registerNative()函数要完 阅读全文

posted @ 2021-12-16 09:10 鸠摩(马智) 阅读(816) 评论(0) 推荐(0) 编辑

2021年12月15日

第44篇-为native方法设置解释执行入口

摘要: 对于Java中的native方法来说,实际上调用的是C/C++实现的本地函数,由于可能会在Java解释执行过程中调用native方法,或在本地函数的实现过程中调用Java方法,所以当两者相互调用时,必须要遵守调用约定,同时要保证在被调用方法执行完成后,调用者的方法能继续向下执行。 在HotSpot 阅读全文

posted @ 2021-12-15 09:51 鸠摩(马智) 阅读(680) 评论(0) 推荐(0) 编辑

2021年12月14日

第43篇-JNI引用的管理(2)

摘要: 之前我们已经介绍了JNIHandleBlock,但是没有具体介绍JNIHandleBlock中存储的句柄,这一篇我们将详细介绍对这些句柄的操作。 JNI句柄分为两种,全局和局部对象引用: (1)大部分对象的引用属于局部对象引用,最终还是调用了JNIHandleBlock来管理,因为JNIHandle 阅读全文

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

2021年12月3日

第42篇-JNI引用的管理(1)

摘要: 在本地函数中会使用Java服务,这些服务都可以通过调用JNIEnv中封装的函数获取。我们在本地函数中可以访问所传入的引用类型参数,也可以通过JNI函数创建新的 Java 对象。这些 Java 对象显然也会受到GC的影响。所以我们需要通过JNI 的局部引用(Local Reference)和全局引用( 阅读全文

posted @ 2021-12-03 09:55 鸠摩(马智) 阅读(761) 评论(0) 推荐(0) 编辑

2021年12月2日

第41篇-JNIEnv与JavaVM的初始化

摘要: JavaVM和JNIEnv的初始化和JVM各模块的初始化都是在JNI_CreateJavaVM()函数中完成。这一篇将详细介绍JavaVM和JNIEnv的初始化过程。 1、初始化JavaVM JavaVM的初始化都是在JNI_CreateJavaVM()函数中完成,调用链如下: JavaMain() 阅读全文

posted @ 2021-12-02 09:07 鸠摩(马智) 阅读(1287) 评论(0) 推荐(0) 编辑

2021年11月10日

第40篇-JNIEnv和JavaVM

摘要: 下面介绍2个与JNI机制相关的类型JNIEnv和JavaVM。 1、JNIEnv JNIEnv一般是是由虚拟机传入,而且与线程相关的变量,也就说线程A不能使用线程B的JNIEnv。而作为一个结构体,它里面定义了JNI系统操作函数。在之前介绍的实例中,可以看到C的Java_TestJNI_set()或 阅读全文

posted @ 2021-11-10 09:48 鸠摩(马智) 阅读(1022) 评论(0) 推荐(1) 编辑

2021年11月9日

第39篇-Java通过JNI调用C/C++函数

摘要: 在某些情况下,Java语言需要通过调用C/C++函数来实现某些功能,因为Java有时候对这些功能显的无能为力,如想使用X86_64 的 SIMD 指令提升一下业务方法中关键代码的性能,又或者想要获取某个体系架构或者操作系统特有功能的支持。为了能在Java 代码中调用 C/C++函数,JVM提供了Ja 阅读全文

posted @ 2021-11-09 13:55 鸠摩(马智) 阅读(3630) 评论(0) 推荐(1) 编辑

2021年11月8日

第38篇-解释执行之方法调用小实例

摘要: 这一篇我们介绍一下解释执行的main()方法调用解释执行的add()方法的小实例,这个例子如下: package com.classloading; public class TestInvokeMethod { public int add(int a, int b) { return a + b 阅读全文

posted @ 2021-11-08 14:00 鸠摩(马智) 阅读(484) 评论(0) 推荐(0) 编辑

2021年11月4日

第37篇-Interpreter::_invoke_return_entry等例程

摘要: 我们在之前介绍过return字节码指令的执行逻辑,这个字节码指令只会执行释放锁和退出当前栈帧的操作,但是当控制权转移给调用者时,还需要恢复调用者的栈帧状态,如让%r13指向bcp、%r14指向局部变量表等,另外还需要弹出压入的实参、跳转到调用者的下一个字节码指令继续执行,而这一切操作都是由Inter 阅读全文

posted @ 2021-11-04 10:10 鸠摩(马智) 阅读(322) 评论(0) 推荐(0) 编辑

2021年11月3日

第36篇-return字节码指令

摘要: 方法返回的字节码相关指令如下表所示。 0xac ireturn 从当前方法返回int 0xad lreturn 从当前方法返回long 0xae freturn 从当前方法返回float 0xaf dreturn 从当前方法返回double 0xb0 areturn 从当前方法返回对象引用 0xb1 阅读全文

posted @ 2021-11-03 10:58 鸠摩(马智) 阅读(663) 评论(0) 推荐(1) 编辑

导航