JVM-程序编译与代码早期(编译期)优化
早期(编译期)优化
一、Javac编译器
1.Javac的源代码与调试
Javac的源代码放在JDK_SRC_HOME/langtools/src/shares/classes/com/sun/tools/javac中,除了JDK自身的API之外,就只引用了JDK_SRC_HOME/langtools/src/shares/classes/com/sun/*里面的代码,调试环境建立起来简单方便,因为基本上不需要处理依赖关系。
编译过程大致可以分成3个过程:
(1)解析与填充符号表过程
(2)插入式注释处理器的注解过程处理
(3)分析与字节码生成过程
Javac编译动作的入口是com.sun.tools.javac.main,JavaCompikler类,上述3个过程的代码逻辑集中在这个类的compiler()和compiler2()方法中。
2.解析与填充符号表
解析步骤包括词法分析和语法分析两个过程
(1)词法、语法分析
词法分析是将源代码的字节流变成标记(Token)集合,单个字符是程序编码过程的最小元素,而标记则是编译过程的最小元素。
在Javac的源代码中,词法分析过程由com.sun.tools.javac.parser.Scanner类来实现。
词法分析是根据Token序列构造抽象语法树的过程,抽象语法是一种用来描述程序代码语法结构的树形表示方式,语法树的每一个节点都代表着程序代码中的一个语法结构。
语法分析过程由com.sun.tools.javac.parser.Parse类来实现,这个阶段产生出抽象语法树有com.sun.tools.javac.tree.JTree类表示,经过这个步骤之后,编译器就基本不会再对源代码文件进行操作了,后续的操作都建立在抽象语法树上。
(2)填充符号表
符号表(Symbol Table)是由一组符号地址和符号信息构成的表格。
在语法分析中,符号表所登记的内容将用于语法分析检查和产生中间代码。
在目标代码生成阶段,当对符号名进行地址分配时,符号表是地址分配的依据。
在Javac源代码中,填充符号表的过程由com.sun.tools.javac.compiler.Enter类来实现,此过程的出口是一个待处理列表(ToDoList),包含;了每一个编译单元的抽象语法树的顶级节点以及package-info-java的顶级节点。
3.注解处理器
在Javac源码中,插入式注解处理器的初始化过程是在initProcessAnnotations()方法中完成的,而它的执行过程则是在ProcessAnnotations()方法中完成的。这个方法判断是否有新的注解处理器需要执行,如果有的话,通过com.sun.tools.javac.Processing.JavacProvcessingEnviroment类的doProcessing()方法生成一个新的JavaCompiler对象对编译的后续步骤进行处理。
4.语义分析与字节码生成
(1)标注检查:内容包括诸如变量使用前后是否已被声明,变量与赋值之间的数据类型是否能够匹配等。在标注检查步骤中,还有一个重要的动作,称为常量折叠。
标注检查步骤在javac源代码中实现类是com.sun.tools.javacComp.Attr类和com.sun.tools.javac.comp.Check类。
(2)数据及控制分析
对程序上下文逻辑更进一步的验证,它可以检查出诸如程序局部变量在使用前后是否有赋值,方法的每一条路径是否都有返回值,是否所有的受检查异常都被正确出来了等问题。
在Javac的源代码中,数据及控制流分析的入口是flow()方法,具体操作是由com.sun.tools.javac.comp.Flow类来完成的。
(3)解语法糖
语法糖(Syntatic Sugar),也称糖衣语法,指在计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便使用。
在Javac的源代码中,解语法糖的过程由的desugar()方法触发,在com.dun.tools.javac.comp.TransTypes类和com.sun.tools.javac.comp.Lower类中完成。
(4)字节码生成
字节码生成是Javac编译过程的最后一个阶段,在Javac源代码里面有com.sun.tolls.javac.jvm.Gen类来完成。
完成了语法树的遍历和调整之后,就会把填充了所有需要信息的符号表交给com.sun.tolls.javac.jvm.ClassWrite类,由这个类的WiteClass()方法输出字节码,生成最终的class文件。到此为止整个编译过程就结束了。
二、Java语法糖
1.泛型与类型擦除
C#里面泛型无论在程序源码中,编译后的IL中,货值运行期的CLR中,都是切实存在的,List<int>与List<string>就两个不同稍微类型,它们在系统运行期生成,有自己的虚方法表和,类型数据,这种实现机制称为类型膨胀,基于这种方法实现的泛型称为真是泛型。
Java语言中的泛型不一样,它只在程序源代码中存在,在编译后的字节码文件中,就已经替换为原来的原生类型了,并且在相应的地方插入了强制转型代码,因此,对于运行期的Java语言来说,ArrayList<String>与ArrayList<int>就是同一个类,所以泛型技术实际上是Java语言的一颗语法糖,java语言中的泛型实现方法称为类型擦除,基于这种方法的泛型称为伪泛型。
虚拟机规范中引入了诸如Signature,LocalVariableType等新的属性用于解决伴随泛型而来的参数类型识别问题。
2.自动装箱、拆箱与遍历循环
自动装箱、拆箱在编译之后转化成了对应的包装盒还原方法,而遍历循环则把代码还原成迭代器的实现。
包装类的“==”运算在不遇到算术符运算的情况下不会自动拆箱,以及它们equals()方法不处理数据转型的关系。
3.条件编译
Java语言可以进行条件编译,方法就是使用条件为常量的if语句。
Java语言中条件编译的实现是,Java语言的一颗语法糖,根据布尔常量的真假,编译器将会把分支中不成立的代码清除掉。这一项工作将在编译器解除语法糖阶段(com.sun.tools.javac.comp.Lower类中)实现。
JVM-程序编译与代码早期(编译期)优化的更多相关文章
- 《深入理解Java虚拟机》-----第10章 程序编译与代码优化-早期(编译期)优化
概述 Java语言的“编译期”其实是一段“不确定”的操作过程,因为它可能是指一个前端编译器(其实叫“编译器的前端”更准确一些)把*.java文件转变成*.class文件的过程;也可能是指虚拟机的后端运 ...
- (转)unity3D 如何提取游戏资源 (反编译)+代码反编译
原帖:http://bbs.9ria.com/thread-401140-1-1.html 首先感谢 雨松MOMO 的一篇帖子 教我们怎么提取 .ipa 中的游戏资源.教我们初步的破解unity3d资 ...
- 小师妹学JVM之:深入理解JIT和编译优化-你看不懂系列
目录 简介 JIT编译器 Tiered Compilation分层编译 OSR(On-Stack Replacement) Deoptimization 常见的编译优化举例 Inlining内联 Br ...
- JVM性能优化系列-(5) 早期编译优化
5. 早期编译优化 早起编译优化主要指编译期进行的优化. java的编译期可能指的以下三种: 前端编译器:将.java文件变成.class文件,例如Sun的Javac.Eclipse JDT中的增量式 ...
- Javac早期(编译期)
从Sun Javac的代码来看,编译过程大致可以分为3个过程: 解析与填充符号表过程. 插入式注解处理器的注解处理过程. 分析与字节码生成过程. Javac编译动作的入口是com.sun.tools. ...
- 深入了解JVM虚拟机8:Java的编译期优化与运行期优化
java编译期优化 java语言的编译期其实是一段不确定的操作过程,因为它可以分为三类编译过程:1.前端编译:把.java文件转变为.class文件2.后端编译:把字节码转变为机器码3.静态提前编译: ...
- 【深入理解JAVA虚拟机】第4部分.程序编译与代码优化.1.编译期优化。这章编译和实战部分没理解通,以后再看。
1.概述 1.1.编译器的分类 前端编译器:Sun的Javac. Eclipse JDT中的增量式编译器(ECJ)[1]. 把*.java文件转变成*.class文件 JIT编译器:HotSpot ...
- Android 程序分析环境搭建-Android 9 -代码下载编译
Android 9 -代码下载编译 一,翻墙下载: 1.背景: 背景: 现在Android framework 开发的同学,整体在公司里面解一些无关痛痒的bug,对于Android framework ...
- java编译期优化
java语言的编译期其实是一段不确定的操作过程,因为它可以分为三类编译过程: 1.前端编译:把.java文件转变为.class文件 2.后端编译:把字节码转变为机器码 3.静态提前编译:直接把*.ja ...
随机推荐
- 如何利用php array_multisort函数 对数据库排序
数据库中有4个字段分别是id,volume,edition,name. 要求对查询结果按照volume+edition从大到小排序.下面将一下array_multisort函数array_multis ...
- 异步加载JS的4种方式(详解)
方案1:$(document).ready <!DOCTYPE html> <html> <head> <script src="http://co ...
- Android 进阶 Android 中的 IOC 框架 【ViewInject】 (下)
上一篇博客我们已经带大家简单的吹了一下IoC,实现了Activity中View的布局以及控件的注入,如果你不了解,请参考:Android 进阶 教你打造 Android 中的 IOC 框架 [View ...
- .Net最佳实践3:使用性能计数器收集性能数据
本文值得阅读吗? 本文讨论我们如何使用性能计数器从应用程序收集数据.我们将先了解的基本知识,然后我们将看到一个简单的示例,我们将从中收集一些性能数据. 介绍: - 我的应用程序的性能是最好的,像火箭 ...
- python matplotlib 中文显示参数设置
python matplotlib 中文显示参数设置 方法一:每次编写代码时进行参数设置 #coding:utf-8import matplotlib.pyplot as pltplt.rcParam ...
- jQuery判断当前元素是第几个元素
$("ul li").click(function () { var index = $("ul li").index(this); alert(index); ...
- CSS3的chapter2
CSS的选择符有很多,大致分为八种: 通配选择符 元素选择符 群组选择符 关系选择符 id及class类选择符 伪类选择符 属性选择符 伪对象选择符 1.通配选择符: 可以使用模糊指定的方式来对对象进 ...
- C#MVC使用二进制流显示图片
关于显示图片的最好方法当然是img 的src直接指向地址,简单实用.但是有时候也会使用到使用图片流显示图片的方法.实现也比较简单(在C# mvc中,java的不了解).具体如下: 1.前台cshtml ...
- 通过配置的方式Autofac 《第三篇》
一.基本配置 1.通过配置的方式使用Autofac <?xml version="1.0"?> <configuration> <configSect ...
- winform小程序---猜拳小游戏
因为学的时间不长,所以借鉴了一些资料做了这个小程序,大家共同学习,共同进步.感觉很有自信,世上无难事,只怕有心人. using System; using System.Collections.Gen ...