Java的编译原理

article/2025/8/24 18:40:00

目录

  • 概述
  • Java中的前端编译
    • 解析与填充符号表
    • 插入式注解处理器
    • 语义分析与字节码生成
  • Java中的后端编译
    • 编译器与解释器
    • 编译对象与触发条件
    • 编译过程
  • Java的后端编译优化技术
    • 公共子表达式消除
    • 数组边界检查消除
    • 方法内联
    • 逃逸分析
  • 参考资料

概述

java语言的"编译期"分为前端编译和后端编译两个阶段。前端编译是指把*.java文件转变成*.class文件的过程; 后端编译(JIT, Just In Time Compiler)是指把字节码转变成机器码的过程。

在编译原理中, 将源代码编译成机器码, 主要经过下面几个步骤:

Java中的前端编译

java的前端编译(即javac编译)可分为解析与填充符号表、插入式注解处理器的注解处理、分析与字节码生成等三个过程。

解析与填充符号表

解析步骤包括词法分析和语法分析两个阶段。

词法分析是将源代码的字符流转变为标记(Token)集合, 单个字符是程序编写过程的最小单位, 而标记则是编译过程的最小单位, 关键字、变量名、字面量、运算符都可以成为标记。

语法分析是根据Token序列构造抽象语法树的过程, 抽象语法树(AST)是一种用来描述程序代码语法结构的树形表示方式, 语法树的每一个节点都代表着程序代码中的一个语法结构, 如包、类型、修饰符、运算符、接口、返回值都可以是一个语法结构。 

符号表是由一组符号地址和符号信息构成的表格。在语法分析中, 符号表所登记的内容将用于语义检查和产生中间代码。在目标代码生成阶段, 符号表是当对符号名进行地址分配时的依据。

插入式注解处理器

插入式注解处理器可以看做是一组编译器的插件, 在这些插件里面, 可以读取、修改、添加抽象语法树中的任意元素。如果这些插件在处理注解期间对语法数进行了修改, 编译器将回到解析与填充符号表的过程重新处理, 直到所有插入式注解处理器都没有再对语法数进行修改为止, 每一次循环称为一个Round。

语义分析与字节码生成

语法分析后, 编译器获得了程序代码的抽象语法树表示, 语法数能表示一个结构正确的源程序的抽象, 但无法保证源程序是符合逻辑的。而语义分析的主要任务是对结构正确的源程序进行上下文有关性质的审查。

Javac的编译过程中, 语义分析过程分为标注检查、数据及控制流分析两个步骤。

标注检查的内容包括诸如变量使用前是否已被声明、变量与赋值之间的数据类型是否能够匹配等。另外在标注检查步骤中, 还有一个重要的动作称为常量折叠。

数据及控制流分析是对程序上下文逻辑更进一步的验证, 他可以检查出诸如程序局部变量在使用前是否有赋值、方法的每条路径是否都有返回值、是否所有的受查异常都被正确处理等问题。

Java中常用的语法糖有泛型、变长参数、自动装箱/拆箱、遍历循环、条件编译等等。虚拟机运行时并不支持这些语法, 它们在编译阶段还原回简单的基础语法结构, 这个过程称为解语法糖

字节码生成是Javac编译过程的最后一个阶段, 它将前面各个步骤所生成的信息(语法数、符号表)转化成字节码写到磁盘中, 另外还进行少量的代码添加(如实例构造器)和转换工作。

Java中的后端编译

在部分商用虚拟机中, Java程序最初是通过解释器进行解释执行的, 当虚拟机发现某个方法或代码块的运行特别频繁时, 就会把这些代码认定为"热点代码"。为了提高热点代码的执行效率, 在运行时, 虚拟机将会把这些代码编译成与本地平台相关的机器码, 并进行各种层析的优化, 完成这个任务的编译器称为即时编译器(JIT编译器)。

编译器与解释器

HotSpot虚拟机中内置了两个即时编译器, 分别称为Client Compiler(C1编译器)和Server Compiler(C2编译器)。在HotSpot虚拟机中, 默认采用解释器与其中一个编译器直接配合的方式工作, 程序使用哪个编译器, 取决于虚拟机运行的模式, HotSpot虚拟机会根据自身版本与宿主机器的硬件性能自动选择运行模式, 这种解释器与编译器搭配使用的方式在虚拟机中称为"混合模式"(Mixed Mode)。在个人机器上, 通过java -version命令可查看自己安装的JDK中是哪种模式。

在JDK 1.7的Server模式虚拟机中, 默认开启分层编译的策略。分层编译根据编译器编译、优化的规模与耗时, 划分出不同的编译层次:

  • 第0层, 程序解释执行, 解释器不开启性能监控功能, 可触发第1层编译。
  • 第1层, 也称为C1编译, 将字节码编译为本地代码, 进行简单可靠的优化, 如有必要将加入性能性能监控的逻辑。
  • 第2层(或2层以上), 也称为C2编译, 也是将字节码编译为本地代码, 但是会启用一些编译耗时较长的优化, 甚至会根据性能监控信息进行一些不可靠的激进优化。

实施分层编译后, C1编译器和C2编译器将会同时工作, 用C1编译器获取更高的编译速度, 用C2编译器获取更好的编译质量。

编译对象与触发条件

在运行过程中会被即时编译器编译的"热点代码"有如下两类:

  • 被多次调用的方法。
  • 被多次执行的循环体。

对于第一种情况, 编译器会以整个方法作为编译对象, 这种编译也是虚拟机中标准的JIT编译方式。而对于第二种, 尽管编译动作是由循环体所触发的, 但编译器依然会以整个方法(而不是单独的循环体)作为编译对象, 这种编译方式因为编译发生在方法执行过程之中, 因此形象的称之为栈上替换(即OSR编译)。

判断是否需要触发即时编译, 需要先识别出热点代码, 这个行为称之为热点探测。目前主要的热点探测判定方式有以下两种:

  • 基于采样的热点探测: 虚拟机周期性地检查各个线程的栈顶, 如发现某个方法经常出现在栈顶, 它就是"热点方法"。好处是简单高效, 还可以获取方法调用关系; 缺点是很难精确的确认一个方法的热点, 容易受到线程阻塞或别的外界因素干扰。
  • 基于计数器的热点探测: 虚拟机会为每个方法(甚至是代码块)建立计数器, 统计方法的执行次数, 如果执行次数超过一定的阈值就认为是"热点方法"。

在HotSpot虚拟机中使用的是第二种————基于计数器的热点探测, 它为每个方法准备了两类计数器: 方法调用计数器和回边计数器。在确定虚拟机运行参数的前提下, 这两个计数器都有一个的确定的阈值, 当计数器超过阈值溢出, 就会触发JIT编译。

方法调用计数器用于统计方法被调用的次数; 回边计数器用于统计一个方法中循环体代码执行的次数, 在字节码中遇到控制流向后跳转的指令称为"回边"。关于这两种计数器, 读者可参阅<<深入理解Java虚拟机>>, 这里不多做深入分析。

编译过程

在默认设置下, 无论是方法调用产生的标准JIT编译请求, 还是OSR编译请求, 虚拟机在代码编译器还未完成之前, 都仍然将按照解释方式继续执行, 而编译动作则在后台的编译线程中进行。

Java的后端编译优化技术

公共子表达式消除

如果一个表达式E已经计算过了,并且从先前的计算到现在E中所有变量的值都没有发生变化,那E的这次出现就成为了公共子表达式。对于这种表达式, 没必要花时间再对它进行计算, 只需要直接用前面计算过的表达式结果替代E就可以了。

数组边界检查消除

顾名思义就是如果编译器根据数据流分析, 访问数组的下标没有越界, 那么就可以消除数组的边界检查, 这样能节省很多的条件判断操作, 提升程序性能。

方法内联

内联函数就是在程序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来直接进行替换。

逃逸分析

逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他地方中,称为方法逃逸。甚至还有可能被外部线程访问到,譬如赋值给类变量或可以在其他线程中访问的实例变量,称为线程逃逸。

如果能证明一个对象不会逃逸到方法或线程外,则可能为这个变量进行一些高效的优化, 如栈上替换、同步消除、标量替换。


http://chatgpt.dhexx.cn/article/iePyM4ml.shtml

相关文章

Java反编译

反编译的过程与编译刚好相反&#xff0c;就是将已编译好的编程语言还原到未编译的状态&#xff0c;也就是找出程序语言的源代码。就是将机器看得懂的语言转换成程序员可以看得懂的语言。Java语言中的反编译一般指将class文件转换成java文件。 Java常用反编译工具 本文主要介绍…

编译 java_如何编译java

展开全部 用命令32313133353236313431303231363533e58685e5aeb931333337613139提示符编译java程序的步骤&#xff1a; 1.先新建文本文档&#xff0c;输入自己的java程序。 这里我写一个简单的java程序&#xff0c;来做示范。 import java.util.*; public class HelloDate{ publ…

Java是如何编译运行的?

先看一个示例&#xff1a; public class Hello {public static void main(String[] args){System.out.println("Hello World !");Test test new Test();test.print();} } class Test{void print() {System.out.println("Hello Java !");} }如果源文件有多…

Java| 编译和反编译

什么是编程语言? 在介绍编译和反编译之前&#xff0c;我们先来简单介绍下编程语言&#xff08;Programming Language&#xff09;。编程语言&#xff08;Programming Language&#xff09;分为低级语言&#xff08;Low-level Language&#xff09;和高级语言&#xff08;High-…

安装java编译器

安装JDK。 参考&#xff1a;https://www.cnblogs.com/mr-wuxiansheng/p/6850437.html 1.官网下载 Java SE Development Kit 13.0.1 &#xff08;由于是访问国外网站&#xff0c;所以会比较慢。&#xff09; 最好下载EXE版本的&#xff0c;这样什么都不用管&#xff0c;点安装…

java编译和运行

java应用程序的基本结构编写源文件保存源文件额外附加编译器&#xff08;javac.exe&#xff09;解释器&#xff08;java.exe&#xff09; 总结&#xff1a; 假如我的B.java源文件在C:\Users\AUSU\Desktop\ts里面 一般都是进入到这个目录里面编译解释 编译&#xff1a;javac …

java如何编译运行?

对于一个Java开发者来说我们编写的程序肯定是要运行才能体现出作用来&#xff0c;对于新手同学来说你知道如何去编译和运行一个Java程序吗&#xff1f;小千今天就来告诉大家&#xff0c;步骤很详细带好小本本哦。 Java程序编译运行步骤 1.首先我们在windows环境下需要安装好Jav…

JVM(一)一文读懂Java编译全过程

一文读懂Java编译全过程 java代码首先要通过前端编译器编译成.class字节码文件&#xff0c;然后再按一定的规则加载到JVM&#xff08;java 虚拟机&#xff09;内运行&#xff0c;有三种运行方式&#xff0c;解释模式&#xff08;javac&#xff09;、编译模式&#xff08;C1 JIT…

无需插件修改chrome浏览器UA标识为手机版

可能在手机上我们可以很方便的操作将网页的UA设置为电脑版或者是其他的&#xff0c;但是在电脑上一般没有直接的操作修改&#xff0c;网上的经验也一般为使用User-Agent Switcher 插件,修改。其实使用开发者工具就已经能够很方便的修改UA了 首先在对应的页面按下F12&#xff0c…

使用PC端谷歌Chrome浏览器浏览手机网页 修改PC端谷歌Chrome浏览器UA

废话不多说直接上干货&#xff08;快下班了&#xff09;&#xff1a; 1.进入你想要审查元素的网站&#xff0c;比如www.baidu.com&#xff1b; 2.按F12召唤开发者窗口&#xff1b; 3.点击下图框出来的三个点&#xff1a; 4.点击下图框出来的选项&#xff1a; 5.将下面框选住…

【测试】抓包获取浏览器UA,并使用Chrome 调试工具模拟手机

抓包获取浏览器UA 首先需要先安装charles&#xff0c;在http的请求头当中可以看到User-Agent&#xff0c;复制该User-Agent的内容 如果你是前端开发&#xff0c;也可通过以下代码获取UA $(‘body’).html(navigator.userAgent);构造UA 然后打开chrome浏览器的调试工具&…

自定义浏览器UA标识

正文 手机浏览器改成下面这段&#xff0c;可以享受到百度的纯净浏览。 Mozilla/5.0 (Linux; U; Android 10; zh-CN; 2014811 Build/QQ3A.200805.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/78.0.2564.116 Quark/3.8.2.126 Mobile Safari/537.36 T7/10.…

修改浏览器UA的作用汇总

1.浏览器标识&#xff08;UA&#xff09; 可以使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件&#xff0c;从而判断用户是使用电脑浏览还是手机浏览&#xff0c;让网页作出自动的适应。    可理解为网站通过…

一篇文章带你了解清楚什么是UA

最近在做一部分的UA的统计、正好做下记录、有需要的同学也可以借鉴一下 一、首先讲一下UA是什么 UA&#xff0c;全称为“User Agent”&#xff0c;中文通常直译为“用户代理”&#xff0c;但从其产生作用的机制来看&#xff0c;或许称之为“浏览器标识”或“浏览器名片”更为妥…

小白想学大数据?

一.大数据领域的从业人员,应该牢牢把握2018年大数据这三个大的技术方向: 1、Hadoop大数据开发方向; 2、数据挖掘、数据分析和机器学习方向; 3、大数据运维和云计算方向。精通任何方向之一者,均会前(钱)途无量。 3个方向中,大数据开发是基础。以Hadoop开发工程师为例,…

Java开发者,我到底要不要学大数据开发?

一入编程深似海&#xff0c;从此女神是路人。没办法&#xff0c;这行就这样。你不学Spring&#xff0c;总不是跑去学JVM/微服务架构/分布式去了&#xff0c;不断学习根本避免不了。所以关键在于把时间投在学什么上比较划算。 明确表达我的观点&#xff0c;作为一名Javaer进阶大…

从0开始学大数据-数据仓库建模

为什么要数据仓库建模 数据模型是数据组织和存储方法&#xff0c;它强调从业务、数据存取和使用角度合理存储数据。有了适合业务和基础数据存储环境的模型&#xff0c;那么大数据就能获得以下好处&#xff1a; 性能&#xff1a;良好的数据模型能帮助我们快速查询所需要的数据&a…

【金猿案例展】某国家级研究所——组学大数据分析平台建设

荣联科技集团案例 本案例由荣联科技集团投递并参与“数据猿年度金猿策划活动——2020大数据产业创新服务企业榜单及奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 大数据时代下&#xff0c;科学大数据已经成为科技创新和社会经济发展的新动力。生物信息学经过近…

零基础学大数据分析现实吗

学习大数据分析已然成为社会的大势所趋&#xff0c;随着传统公司的被迫更新&#xff0c;新兴公司的数据人才增多&#xff0c;大数据技术显得格外的重要。当大数据的大浪凶猛袭来时&#xff0c;要么你冲上浪尖&#xff0c;做时代的弄潮儿&#xff0c;要么被打入海底&#xff0c;…

零基础可以学大数据分析吗

国家的大数据战略实施已经到了关键的落地时期&#xff0c;创新、实体经济都跟大数据分析有着深度的融合&#xff0c;在各行各业都能看到大数据分析师的身影&#xff0c;另外大数据安全管理和立法等方面也进入到了关键时刻&#xff0c;所有这些无不在向人们诉说着一个事实&#…