我在上一章《形象谈JVM-第一章-认识JVM》提到的“翻译”,其实就是我们今天所说的“编译”的概念。

上一章原文链接:https://www.cnblogs.com/xingxiangtan/p/17617654.html

原文:

【 虚拟机的职责是将字节码翻译成对应系统能够识别并执行的机器码,

比如在linux系统,java文件被javac编译器翻译成字节码文件(class文件),jvm将字节码文件翻译成linux能够识别并执行的机器码文件,这样java程序便能够被运行起来了。

java文件是咱人类能看懂的文件,字节码文件是虚拟机能看懂的文件,机器码文件是CPU能看懂的文件。 】

本文将分为两个部分来展开,前端编译与优化和后端编译与优化

讲之前我们先来弄清楚这三个关键词的意思,前端、后端和优化。

前后端:以文件进入JVM之前和之后为基准在区分前后的。

优化:一个高级的翻译将英文作品翻译成中文作品时,绝不会逐字死板的去翻译,而是会在不影响原意的前提下加以文采的修饰,以达到读者更好更快的理解,编译器的优化类似,在编译期,在不影响代码逻辑的前提下,会将复杂优化成简洁的,将缓慢的优化成快速的等等,为了程序更好更快(非绝对)的执行。

前端编译器及优化:

前端编译器包括JDK的Javac、Eclipse JDT中的增量式编译器(ECJ)等等, 咱们讲javac,javac本身就是一个由Java语言编写的程序。

执行javac命令,就是javac编译器解析Java源代码,并生成字节码文件的过程。javac编译过程可以分为四个阶段:

1、词法、语法分析。

词法分析是将源代码的字符流转变为标记集合的过程。

语法分析是根据标记序列构造抽象语法树的过程,抽象语法树(Abstract Syntax Tree,AST)是一种用来描述程序代码语法结构的树形表示方式。

举个形象的例子,上中学,学英语科目,我们要弄懂一句话,首先得知道各个单词的意思,这就对应着词法分析了,然后英语的语法有很多种,首先要搞清楚主谓宾结构,还有从句,后置之类的语法,这个就对应了语法分析,这二者都没问题了就能够弄清楚这一句话的意思了。

2、填充符号表。

类之间是会互相引用的,但在编译阶段,无法确定其具体的地址,所以会使用一个符号来替代。等到被引用类加载时,javac 编译器会将符号替换成具体的内存地址。

比如开学第一天,老师让你去找一个班里的一个名字叫“李小花”的同学,这个“名字”就相当于一个“符号”,你不知道李小花同学坐在哪里,你就大喊李小花的名字,李小花同学听到了,便答应,于是你就看到了李小花坐在三排二座,以后你就知道“三排二座”的同学就是李小花了,这个“三排二座”就相当于“地址值”。

3、注解处理。

JDK 5之后,Java语言提供了对注解的支持,注解在设计上原本是与普通的Java代码一样,都只会在程序运行期间发挥作用的,因此在这个阶段会对注解进行分析,根据注解的作用将其还原成具体的指令集。

4、语义分析与字节码生成。

语义分析的主要任务是对结构上正确的源程序进行上下文相关性质的检查,比如类型检查、控制流检查、数据流检查,等等,再进行字节码的生成,最终输出为class文件。

后端编译器及优化:

后端编译器包括JIT(Just In Time)即时编译器和AOT(Ahead Of Time)提前编译器。

而在解释后端编译器之前我们要先来解释一下解释器

解释器:直接执行用编程语言编写的指令的程序。

编译器:把源代码转换成(翻译)低级语言的程序。(这里所指的低级是越接近于机器则越低级)

如上图,编译器如同“笔译员”,对语言进行转换,输出一份可以被用于执行的文件,解释器如同“口译员”,直接将翻译后的结果输出,不保存任何中间文件。

从这二者的工作模式,可以很容易的联想到它们的优点和缺点

解释器:

优点:启动速度快

缺点:执行速度慢,执行效率低

编译器:

优点:执行效率高

缺点:编译速度(启动速度)慢

接下来咱们继续讲回后端编译器。

JIT(Just In Time)即时编译器

HotSpot虚拟机内置了两个(或三个)即时编译器,在执行的过程中,将热点代码(也就是执行次数比较多的代码)转化为本

地机器码,并做优化,以加速执行效率。

客户端编译器(Client Compiler)和服务端编译器(Server Compiler),简称为C1编译器和C2编译器,第三个是在JDK 10时才出现的、目标是代替C2的Graal编译器。咱们本章节只讲解C1、C2编译器。

在 Java 7 以前,我们需要根据程序的特性选择对应的即时编译器。

对于执行时间较短的,或者对启动性能有要求的程序,我们采用编译效率较快的 C1,对应参数 -client。

对于执行时间较长的,或者对峰值性能有要求的程序,我们采用生成代码执行效率较快的 C2,对应参数 -server。

在分层编译(Tiered Compilation)的工作模式出现以前,HotSpot虚拟机通常是采用解释器与其中一个编译器直接搭配的方式工

作,程序使用哪个编译器,只取决于虚拟机运行的模式,HotSpot虚拟机会根据自身版本与宿主机器的硬件性能自动选择运行模式,用

户也可以使用“-client”或“-server”参数去强制指定虚拟机运行在客户端模式还是服务端模式。

无论采用的编译器是客户端编译器还是服务端编译器,解释器与编译器搭配使用的方式在虚拟机中被称为“混合模式”(MixedMode),

用户也可以使用参数“-Xint”强制虚拟机运行于“解释模式”(Interpreted Mode),这时候编译器完全不介入工作,全部代码都使用

解释方式执行。另外,也可以使用参数“-Xcomp”强制虚拟机运行于“编译模式”(Compiled Mode),这时候将优先采用编译方式执行

程序,但是解释器仍然要在编译无法进行的情况下介入执行过程。

可以通过虚拟机的“-version”命令的输出结果显示出这三种模式:

Java 7 引入了分层编译(对应参数 -XX:+TieredCompilation)的概念,综合了 C1 的启动性能优势和 C2 的峰值性能优势。

分层编译的五个层次

分层编译将 Java 虚拟机的执行状态分为了五个层次。

五个层级分别是:

1、程序解释执行,不开启Profiling(性能监控功能:解释器替编译器收集性能监控信息);

2、进行简单可靠的稳定优化,执行不带 profiling 的 C1 机器码;

3、执行仅带方法调用次数以及循环回边执行次数 profiling 的 C1 机器码;

4、执行带所有 profiling(除第3层的统计信息外,还会收集如分支跳转、虚方法调用版本等全部的统计信息) 的 C1 机器码;

5、执行 C2 机器码。对比C1,C2会启用更多编译耗时更长的优化,还会根据性能监控信息进行一些不可靠的激进优化

通常情况下,C2 代码的执行效率要比 C1 代码的高出 30% 以上。

然而,对于 C1 代码的三种状态,按执行效率从高至低则是 1 层 > 2 层 > 3 层。

其中 1 层的性能比 2 层的稍微高一些,而 2 层的性能又比 3 层高出 30%。

这是因为 profiling 越多,其额外的性能开销越大。

在 5 个层次的执行状态中,1 层和 4 层为终止状态。当一个方法被终止状态编译过后,如果编译后的代码并没有失效,那么 Java 虚拟机是不会再次发出该方法的编译请求的。

如何来理解这个激进优化呢?

激进:有一定的性能提升,但不一定准确可靠

举例:

若在运行的过程中,性能监控到前一百次执行都只是走了1分支,那咱们编译还需要去考虑编译2分支吗?不需要了。

但是如果不编译2分支的代码,之后程序真的走了2分支咋办?直接找五层中的第一层的解释器执行就好了。(在后面的章节中我们会讲解更多的优化策略)

AOT(Ahead Of Time)提前编译器

提前编译器也可称为静态预编译器,因为它不像即时编译器,是在程序一边解释执行,一边进行编译的,而是先单独把文件编译完成。

JIT 优点:

1、启动速度快

2、根据运行情况实时编译生成最优机器指令

3、可以处理动态语言,因为可以在运行时确定类型。

JIT 缺点:

1、占用运行时的资源,可能会导致进程执行时候卡顿

2、识别热点代码需要时间,初始编译不能达到最高性能。

AOT 优点:

1、在程序运行前编译,可以避免在运行时的编译性能消耗和内存消耗

2、程序运行初期就达到最高性能,显著的提高执行效率。

AOT 缺点:

1、启动速度慢

2、不能处理动态语言,因为需要在编译时确定类型。

参考书籍:

深入理解虚拟机-第3版-周志明著

参考资料:

https://blog.csdn.net/Shockang/article/details/117392773

https://zhuanlan.zhihu.com/p/107382276

为什么写文章(若有错误,希望得到你的指正,若有问题,都可评论,我将会积极回复)

在作者刚入行时,会遇到很多无法理解的问题,便经常向前辈请教问题,或是于网络之中苦苦寻找答案,经常被一些晦涩难懂的表达折磨的死去活来,现作者是一名拥有多年经验的IT从业者,希望能够将自己的知识以一种形象的方式输出,先从虚拟机开始分享,之后会写更多的专栏,最新的分享将会先在公众号发布,谢谢读者的关注

形象谈JVM-第二章-认识编译器的更多相关文章

  1. java面向对象编程——第二章 java基础语法

    第二章 java基础语法 1. java关键字 abstract boolean break byte case catch char class const continue default do ...

  2. STL源码分析读书笔记--第二章--空间配置器(allocator)

    声明:侯捷先生的STL源码剖析第二章个人感觉讲得蛮乱的,而且跟第三章有关,建议看完第三章再看第二章,网上有人上传了一篇读书笔记,觉得这个读书笔记的内容和编排还不错,我的这篇总结基本就延续了该读书笔记的 ...

  3. Java基础知识二次学习-- 第二章 基础语法与递归补充

    第二章 基础语法与递归补充   时间:2017年4月24日10:39:18 章节:02章_01节,02章_02节 视频长度:49:21 + 15:45 内容:标识符,关键字与数据类型 心得:由字母,下 ...

  4. Python3-Cookbook总结 - 第二章:字符串和文本

    第二章:字符串和文本 几乎所有有用的程序都会涉及到某些文本处理,不管是解析数据还是产生输出. 这一章将重点关注文本的操作处理,比如提取字符串,搜索,替换以及解析等. 大部分的问题都能简单的调用字符串的 ...

  5. 经典中的品味:第二章 C++基本的对象,类型和值(上)

    摘要: 原创出处: http://www.cnblogs.com/Alandre/ 泥沙砖瓦浆木匠 希望转载,保留摘要,谢谢! 自律,是以积极而主动的态度,去解决人生的痛苦~ 上一章,我们大谈了Hel ...

  6. 【黑金原创教程】【TimeQuest】【第二章】TimeQuest模型角色,网表概念,时序报告

    声明:本文为黑金动力社区(http://www.heijin.org)原创教程,如需转载请注明出处,谢谢! 黑金动力社区2013年原创教程连载计划: http://www.cnblogs.com/al ...

  7. 第二章: Identifiers, Keywords and Types

    一:方法的定义和方法的调用 方法的定义:修饰符 方法的返回值 方法名(参数列表){ 方法体 } 如果没有方法的返回值就写成:void 参数列表:参数类型 参数名 方法的调用:方法名(参数值) 第二天: ...

  8. net core体系-web应用程序-4asp.net core2.0 项目实战(CMS)-第二章 入门篇-快速入门ASP.NET Core看这篇就够了

    .NET Core实战项目之CMS 第二章 入门篇-快速入门ASP.NET Core看这篇就够了   原文链接:https://www.cnblogs.com/yilezhu/p/9985451.ht ...

  9. 实现 RSA 算法之 C 语言实现(第二章)(老物)

    第二章 如何实现应用RSA算法 趁着白天在自家店里的闲暇时间来写写第二章了,假设记住了第一章的各种定理之后,我们又该如何实现RSA密码的加密解密呢?也懒得废话了,直接进入正题吧. 先回顾几个知识点: ...

  10. 我的物联网大学【第二章】:Luat的出世

    壹 启动火种 有一位软件行业的大神,名字叫做许小刚. 小刚是一位憨厚的年轻的码农,嵌入式.后端.前端,无所不能,是一个很牛的物联网全栈工程师,也是一家物联网软件公司的创始人兼CEO. 有次跟我.老陆. ...

随机推荐

  1. 2021-03-23:给定一个正整数组成的无序数组arr,给定一个正整数值K,找到arr的所有子数组里,哪个子数组的累加和等于K并且是长度最大的。返回其长度。

    2021-03-23:给定一个正整数组成的无序数组arr,给定一个正整数值K,找到arr的所有子数组里,哪个子数组的累加和等于K并且是长度最大的.返回其长度. 福大大 答案2021-03-23: 双指 ...

  2. 2022-03-15:给定一棵树的头节点head,原本是一棵正常的树, 现在,在树上多加了一条冗余的边, 请找到这条冗余的边并返回。

    2022-03-15:给定一棵树的头节点head,原本是一棵正常的树, 现在,在树上多加了一条冗余的边, 请找到这条冗余的边并返回. 答案2022-03-15: 1.指向头,入度没有0的.入度没有2的 ...

  3. 2021-07-19:给定一个正数N,比如N = 13,在纸上把所有数都列出来如下: 1 2 3 4 5 6 7 8 9 10 11 12 13,可以数出1这个字符出现了6次,给定一个正数N,如果把1

    2021-07-19:给定一个正数N,比如N = 13,在纸上把所有数都列出来如下: 1 2 3 4 5 6 7 8 9 10 11 12 13,可以数出1这个字符出现了6次,给定一个正数N,如果把1 ...

  4. [MAUI程序设计]界面多态与实现

    目录 需求一:在不同设备上使用不同 UI 外观 定义控件 UI 外观 基于平台自定义配置 需求二:在不同数据类别中使用不同的 UI 外观 定义视图 UI 外观 创建数据模板 创建选择器 定义数据 需求 ...

  5. vue全家桶进阶之路40:Vue3父件传值给子件

    在Vue3中,可以通过props将父组件的数据传递给子组件.具体步骤如下: 在父组件中定义要传递给子组件的数据,可以是data属性中的数据或者是计算属性computed中的数据. 在子组件中通过pro ...

  6. django时区问题的解决

    django时区问题的解决  更新时间:2021年05月18日 09:37:58   作者:Silent丿丶黑羽     我们都知道时区,标准时区是UTC时区,django默认使用的就是UTC时区,我 ...

  7. mysql 新建数据库 排序规则

    utf8_unicode_ci和utf8_general_ci对中.英文来说没有实质的差别.utf8_general_ci校对速度快,但准确度稍差.utf8_unicode_ci准确度高,但校对速度稍 ...

  8. 2019年蓝桥杯C/C++大学B组省赛真题(等差数列)

    题目描述: 数学老师给小明出了一道等差数列求和的题目.但是粗心的小明忘记了一部分的数列,只记得其中N 个整数. 现在给出这N 个整数,小明想知道包含这N 个整数的最短的等差数列有几项? 输入格式 输入 ...

  9. 500代码行代码手写docker-设置网络命名空间

    (4)500代码行代码手写docker-设置网络命名空间 本系列教程主要是为了弄清楚容器化的原理,纸上得来终觉浅,绝知此事要躬行,理论始终不及动手实践来的深刻,所以这个系列会用go语言实现一个类似do ...

  10. WPF入门教程系列二十六——DataGrid使用示例(3)

    WPF入门教程系列目录 WPF入门教程系列二--Application介绍 WPF入门教程系列三--Application介绍(续) WPF入门教程系列四--Dispatcher介绍 WPF入门教程系 ...