深入浅出JVM(七)之执行引擎的解释执行与编译执行

news2025/2/27 2:10:07

执行引擎

hotspot执行引擎结构图

执行引擎分为解释器、JIT即时编译器以及垃圾收集器

执行引擎通过解释器/即时编译器将字节码指令解释/编译为对应OS上的的机器指令

本篇文章主要围绕解释器与即时编译器,垃圾收集器将在后续文章解析

解释执行与编译执行

Java虚拟机执行引擎在执行Java代码时,会有两种选择:解释执行和编译执行

解释执行:通过字节码解释器把字节码解析为机器语言执行

编译执行:通过即时编译器产生本地代码执行

Class文件中的代码到底是解释执行还是编译执行只有Java虚拟机自己才能判断准确

编译过程

编译流程在前一篇文章深入浅出JVM之前端编译过程与语法糖原理已经说明,在本篇文章中不再概述

经典编译原理: 1.对源码进行词法,语法分析处理 2.把源码转换为抽象语法树

javac编译器完成了对源码进行词法,语法分析处理为抽象语法树,再遍历抽象语法树生成线性字节码指令流的过程

剩下的指令流有两种方式执行

  1. 由虚拟机内部的字节码解释器去将字节码指令进行逐行解释 (解释执行)
  2. 或优化器(即时编译器)优化代码最后生成目标代码 (编译执行)

执行引擎流程图

解释器与编译器

解释器

作用: 对字节码指令逐行解释

优点: 程序启动,解释器立即解释执行

缺点: 低效

即时编译器 (just in time compiler)

Java中的"编译期"不确定

  • 可能说的是执行javac指令时的前端编译器 (.java->.class)
  • 也可能是后端编译器JIT (字节指令->机器指令)
  • 还可能是AOT编译器(静态提前编译器) (.java->机器指令)

作用: 将方法编译成机器码缓存到方法区,每次调用该方法执行编译后的机器码

优点: 即时编译器把代码编译成本地机器码,执行效率高,高效

缺点: 程序启动时,需要先编译再执行

执行引擎执行方式

执行引擎执行方式大致分为3种

-Xint: 完全采用解释器执行

-Xcomp: 优先采用即时编译器执行,解释器是后备选择

-Xmixed: 采用解释器 + 即时编译器

hotspot中有两种JIT即时编译器

Client模式下的C1编译器:简单优化,耗时短(C1优化策略:方法内联,去虚拟化,冗余消除)

Server模式下的C2编译器:深度优化,耗时长 (C2主要是逃逸分析的优化:标量替换,锁消除,栈上分配)

分层编译策略:程序解释执行(不开启逃逸分析)可以触发C1编译,开启逃逸分析可以触发C2编译

解释器,C1,C2编译器同时工作,热点代码可能被编译多次

解释器在程序刚刚开始的时候解释执行,不需要承担监控的开销

C1有着更快的编译速度,能为C2编译优化争取更多时间

C2用高复杂度算法,编译优化程度很高的代码

逃逸分析带来的优化

当对象作用域只在某个方法时,不会被外界调用到,那么这个对象就不会发生逃逸

开启逃逸分析后,会分析对象是否发生逃逸,当不能发生逃逸时会进行栈上分配、锁消除、标量替换等优化

栈上分配内存

 //-Xms1G -Xmx1G -XX:+PrintGCDetails 
 public class StackMemory {
     public static void main(String[] args) {
         long start = System.currentTimeMillis();
 ​
         for (int i = 0; i < 10000000; i++) {
             memory();
         }
 ​
         System.out.println("花费时间:"+(System.currentTimeMillis()-start)+"ms");
 ​
         try {
             TimeUnit.SECONDS.sleep(1000);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
     }
 ​
     private static void memory(){
         StackMemory memory = new StackMemory();
     }
 }
复制代码

-XX:-DoEscapeAnalysis 花费时间:63ms (未开启逃逸分析)

-XX:+DoEscapeAnalysis 花费时间:4ms (开启逃逸分析)

默认开启逃逸分析

锁消除

同步加锁会带来开销

锁消除:当加锁对象只作用某个方法时,JIT编译器借助逃逸分析判断使用的锁对象是不是只能被一个线程访问,如果是这种情况下就不需要同步,可以取消这部分代码的同步,提高并发性能

标量替换

标量: 无法再分解的数据 (基本数据类型)

聚合量: 还可以再分解的数据 (对象)

标量替换: JIT借助逃逸分析,该对象不发生逃逸,只作用于某个方法会把该对象(聚合量)拆成若干个成员变量(标量)来代替

默认开启标量替换

 public class ScalarSubstitution {
     static class Man{
         int age;
         int id;
 ​
         public Man() {
         }
     }
 ​
     public static void createInstance(){
         Man man = new Man();
         man.id = 123;
         man.age = 321;
     }
     public static void main(String[] args) {
         long start = System.currentTimeMillis();
 ​
         for (int i = 0; i < 10000000; i++) {
             createInstance();
         }
 ​
         System.out.println("花费时间:"+(System.currentTimeMillis()-start)+"ms");
 ​
         try {
             TimeUnit.SECONDS.sleep(1000);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
     }
 }
复制代码
 //-Xmx200m -Xms200m -XX:+PrintGCDetails 
 //-XX:+DoEscapeAnalysis 设置开启逃逸分析
 //-XX:-EliminateAllocations 设置不开启标量替换 
 //开启逃逸分析 + 关闭标量替换 : 花费时间:93ms
 //开启逃逸分析 + 开启标量替换  : 花费时间:6ms
复制代码

热点代码与热点探测

JIT编译器并不是编译所有的字节码,JIT编译器只编译热点代码

热点代码: 被多次调用的方法 或 方法中多次循环的循环体

栈上替换(OSR): JIT将方法中的热点代码编译为本地机器指令(被多次执行的循环体)

编译对象都是方法,如果是栈上替换则"入口"在方法的循环体开始那里

热点探测功能决定了被调用多少次的方法能成为热点代码

hotspot采用基于计数器的热点探测

  • 方法调用计数器 : 统计方法调用次数
  • 回边计数器 : 统计循环体执行循环次数

方法调用时先判断是否有执行编译后的机器码,有则直接使用方法区的Code cache中的机器码;没有机器码则判断计数器次数是否超过阈值,超过则触发编译,编译后机器码存储在方法区Code cache中使用;最后都没有就使用解释执行

总结

本篇文章将围绕执行引擎,深入浅出的解析执行引擎中的解释器、即时编译器各自执行的优缺点以及原理

执行引擎由解释器、即时编译器、垃圾收集器构成,默认情况下使用解释器与编译器的混合方式执行

即时编译器分为C1、C2编译器,其中C1编译快但优化小,C2开启逃逸分析使用栈上分配、锁消除、标量替换进行优化,编译耗时但是优化大

即时编译器并不是所有代码都编译,而是使用方法技术和循环计数来将热点代码编译成机器码存放在方法区的Code Cache中

在混合执行的模式下,解释器、C1、C2编译器同时工作,分层编译

最后

  • 参考资料

    • 《深入理解Java虚拟机》
    • 部分图片来源于网络

本篇文章将被收入JVM专栏,觉得不错感兴趣的同学可以收藏专栏哟~

觉得菜菜写的不错,可以点赞、关注支持哟~

有什么问题可以在评论区交流喔~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/105354.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

方向图与天线增益

目录 一、方向图 二、增益 一、方向图 天线的方向性是指天线向一定方向辐射电磁波的能力。对于接收天线而言&#xff0c;方向性表示天线对不同方向传来的电磁波具有不同的接收能力。天线的方向性通常用方向图来表示。 在数学里&#xff0c;球坐标系是一种利用球坐标表示一个点…

Linux学习-90-Tomcat下载安装(tar压缩包)

17.20 Tomcat下载安装&#xff08;tar压缩包&#xff09; 访问apache官网下载tomcat压缩包。访问以下链接进行下载tomcat-8.5.83版本&#xff0c;高版本的tomcat存在一些问题影响使用&#xff0c;然后使用 Xftp 上传到/usr/local/src目录中或者使用wget命令直接到/usr/local/s…

SpringBoot:模块探究之spring-boot-cli

Spring Boot CLI 是运行 SpringBoot 命令的命令行工具&#xff0c;能够帮助你快速的构建 Spring Boot 项目。只需要编写简单的 groovy 脚本&#xff0c;即可用最少的代码构建并运行一个完整的 Spring Boot 项目。 Spring Boot CLI 为 SpringCloud 提供了 SpringBoot 命令行功能…

Java面试--CAS

这里写目录标题一、概念二、CAS 如何保证原子性2.1、总线锁定2.2、缓存锁定二、底层原理三、CAS典型应用四、CAS问题4.1、循环时间长&#xff0c;开销很大4.2、只能保证一个共享变量的原子操作4.3、引出来 ABA 问题一、概念 判断内存中某个位置的值是否为预期值&#xff0c;如…

Bootstrap5 表单浮动标签

默认情况下&#xff0c;标签内容一般显示在 input 输入框的上方&#xff1a; 使用浮动标签&#xff0c;可以在 input 输入框内插入标签&#xff0c;在单击 input 输入框时使它们浮动到上方 Bootstrap 实例 <div class"form-floating mb-3 mt-3"> <input ty…

uni.requestPayment使用

前言&#xff1a;由于uni.requestPayment没有封装H5支付方法&#xff0c;我自己封装了统一方法可以多端适用。 代码如下&#xff1a; 有两种方法&#xff1a; 方法1&#xff1a;安装 jweixin-module 包&#xff0c;我的是1.6.0版本->引入->使用 方法2&#xff1a;使用微…

51单片机实训day2——创建Keil工程(一)

以管理员身份打开软件&#xff01;&#xff01;&#xff01;以管理员身份打开软件&#xff01;&#xff01;&#xff01;以管理员身份打开软件&#xff01;&#xff01;&#xff01; 内 容&#xff1a;Keil工程创建 学 时&#xff1a;2学时 知识点&#xff1a;开发固件库介绍…

【Linux】进程替换与shell的模拟实现

目录 一、进程替换 1.1 进程替换的概念 1.2 替换函数 二、命令行解释器-Shell 2.1 shell的实现与运行 2.2 步骤讲解 一、进程替换 1.1 进程替换的概念 当我们使用 fork 函数创建子进程后&#xff0c;父子进程各自执行父进程代码的一部分。那如果创建的子进程想要执行一…

UG/NX二次开发Siemens官方NXOPEN实例解析—2.4 File2Points

列文章目录 UG/NX二次开发Siemens官方NXOPEN实例解析—2.1 AssemblyViewer UG/NX二次开发Siemens官方NXOPEN实例解析—2.2 Selection UG/NX二次开发Siemens官方NXOPEN实例解析—2.3 Selection_UIStyler UG/NX二次开发Siemens官方NXOPEN实例解析—2.4 File2Points 前言 随着…

Python开发的编译神器PyCharm----测试从业来编写Python脚本最钟意的工具

目录 前言&#xff1a; 一、PyCharm简介 二、PyCharm下载与安装 1、下载 2、安装 三、PyCharm新增Python项目 步骤1、新增 步骤2、路径配置 步骤3、环境选择 步骤4、 项目运行 四、画圣诞树 前言&#xff1a; 本文将为大家介绍PyCharm下载安装与初步的使用&#xff0c;初…

外汇天眼:美国11月独栋房屋建设跌至两年半低点!

美国商务部周二公布了这份令人沮丧的报告&#xff0c;此前周一有消息称&#xff0c;12月份房屋建筑商信心连续第12个月出现创纪录的下滑。美国11月独栋房屋建设跌至两年半低点&#xff0c;未来建筑许可大幅下滑&#xff0c;因抵押贷款利率上升继续打压楼市活动。 具体数据显示&…

(十九)Vue之组件和模块概念

文章目录传统编程组件化编程模块模块化组件化Vue学习目录 上一篇&#xff1a;&#xff08;十八&#xff09;Vue之生命周期 传统编程 一个html引入大量的CSS、JS文件&#xff0c;使得结构混乱、代码复用率低 传统方式编写应用存在的问题&#xff1a; 1.依赖关系混乱、不好维护…

某讯滑块验证码反汇编分析-第三章

某讯滑块验证码反汇编分析-第三章collect明文处理vData明文处理collect明文处理 上一篇已经跟到明文的拼接函数&#xff0c;接下来看看get函数的返回值&#xff0c;对什么进行拼接。 在这一次运行中&#xff0c;第一次get返回的是一个10&#xff0c;是怎么计算出来的呢&#x…

[XCTF]red_green(难度2)

得到一个乱码的图片&#xff0c;查看信息&#xff0c;联系“red_green” 目录 前言 一、题目重述 二、解题思路 1.套路来一遍 2.过程中注意到以下两点&#xff1a; &#xff08;1)stegsolve图层中只有red/green&#xff0c;与题目暗合 &#xff08;2)zsteg查看隐写信息发…

springboot+jsp实验室管理系统fu1ju-

目录 第一章 绪论 5 1.1 研究背景 5 1.2系统研究现状 5 1.3 系统实现的功能 6 1.4系统实现的特点 6 1.5 本文的组织结构 6 第二章开发技术与环境配置 7 2.1 Java语言简介 7 2.2JSP技术 8 2.3 MySQL环境配置 8 2.4 MyEclipse环境配置 9 2.5 mysql数据库介绍 9 2.6 B/S架构 9 第三…

2022年度安徽省职业院校技能大赛中职组“网络搭建与应用”赛项竞赛试题

2022年度安徽省职业院校技能大赛 中职组“网络搭建与应用” 赛项竞赛 &#xff08;总分1000分&#xff09; 竞赛说明 一、竞赛内容分布 “网络搭建与应用”竞赛共分三个部分&#xff0c;其中&#xff1a; 第一部分&#xff1a;网络搭建及安全部署项目&#xff08;500分&…

SpringCloud-Feign远程调用

&#x1f341;Feign的介绍 Feign是一个声明式的http客户端&#xff0c;官方地址: https://github.com/0penFeign/feign作用就是帮助我们优雅的实现http请求的发送&#xff0c;解决上面提到的问题。 &#x1f341;定义和使用Feign客户端 1.引入依赖 在order-service服务的po…

【PyTorch Geometric】工具包安装部署 过程记录(图模型学习 需要安装的工具包);图神经网络 工具包安装过程记录

目录 部署过程下载别的版本试试部署过程 在常规的安装过程中,若直接通过pip,老师讲 大概率无法成功安装。比较正规的安装方法是,下载好工具包,手动安装。 首先通过 Jupyter Notebook打开配置文档: 有些步骤在该文档中。 点击上图中的超链接,进入对应的 GitHub。 进去…

Linux进程间通信(一):匿名管道的原理和使用

文章目录一、前言二、什么是匿名管道&#xff1f;三、匿名管道的原理三、匿名管道的创建四、匿名管道实现数据传输五、匿名管道实现进程控制六、匿名管道特点总结一、前言 &#xff08;在阅读本文前&#xff0c;需要具备Linux基础IO的基本知识&#xff09;  在某些特定情况下…

【Linux】Linux下基本指令(二)

作者&#xff1a;一个喜欢猫咪的的程序员 专栏&#xff1a;《Linux》 喜欢的话&#xff1a;世间因为少年的挺身而出&#xff0c;而更加瑰丽。 ——《人民日报》 目录 1. Linux基本指令&#xff1a;&#xff08;续&#xff09; 1.1man指令&am…