早期(编译期)优化

一、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-程序编译与代码早期(编译期)优化的更多相关文章

  1. 《深入理解Java虚拟机》-----第10章 程序编译与代码优化-早期(编译期)优化

    概述 Java语言的“编译期”其实是一段“不确定”的操作过程,因为它可能是指一个前端编译器(其实叫“编译器的前端”更准确一些)把*.java文件转变成*.class文件的过程;也可能是指虚拟机的后端运 ...

  2. (转)unity3D 如何提取游戏资源 (反编译)+代码反编译

    原帖:http://bbs.9ria.com/thread-401140-1-1.html 首先感谢 雨松MOMO 的一篇帖子 教我们怎么提取 .ipa 中的游戏资源.教我们初步的破解unity3d资 ...

  3. 小师妹学JVM之:深入理解JIT和编译优化-你看不懂系列

    目录 简介 JIT编译器 Tiered Compilation分层编译 OSR(On-Stack Replacement) Deoptimization 常见的编译优化举例 Inlining内联 Br ...

  4. JVM性能优化系列-(5) 早期编译优化

    5. 早期编译优化 早起编译优化主要指编译期进行的优化. java的编译期可能指的以下三种: 前端编译器:将.java文件变成.class文件,例如Sun的Javac.Eclipse JDT中的增量式 ...

  5. Javac早期(编译期)

    从Sun Javac的代码来看,编译过程大致可以分为3个过程: 解析与填充符号表过程. 插入式注解处理器的注解处理过程. 分析与字节码生成过程. Javac编译动作的入口是com.sun.tools. ...

  6. 深入了解JVM虚拟机8:Java的编译期优化与运行期优化

    java编译期优化 java语言的编译期其实是一段不确定的操作过程,因为它可以分为三类编译过程:1.前端编译:把.java文件转变为.class文件2.后端编译:把字节码转变为机器码3.静态提前编译: ...

  7. 【深入理解JAVA虚拟机】第4部分.程序编译与代码优化.1.编译期优化。这章编译和实战部分没理解通,以后再看。

    1.概述 1.1.编译器的分类 前端编译器:Sun的Javac. Eclipse JDT中的增量式编译器(ECJ)[1].  把*.java文件转变成*.class文件 JIT编译器:HotSpot ...

  8. Android 程序分析环境搭建-Android 9 -代码下载编译

    Android 9 -代码下载编译 一,翻墙下载: 1.背景: 背景: 现在Android framework 开发的同学,整体在公司里面解一些无关痛痒的bug,对于Android framework ...

  9. java编译期优化

    java语言的编译期其实是一段不确定的操作过程,因为它可以分为三类编译过程: 1.前端编译:把.java文件转变为.class文件 2.后端编译:把字节码转变为机器码 3.静态提前编译:直接把*.ja ...

随机推荐

  1. [attribute] 匹配包含给定属性的元素

    描述: 查找所有含有 id 属性的 div 元素 HTML 代码: <div> <p>Hello!</p> </div> <div id=&quo ...

  2. html5 canvas 笔记五(合成与裁剪)

    组合 Compositing globalCompositeOperation syntax: globalCompositeOperation = type 注意:下面所有例子中,蓝色方块是先绘制的 ...

  3. SVN merge的主干,分支的相互合并操作

    本文只研究了 在本地如何进行主干,分支的相互合并 的操作:从主干到分支,从分支到主干. 本地客户端工具是tortoisesvn 测试用例. 1.本地添加test文件夹 在test文件夹下分别建立tru ...

  4. Oracle 流复制实践笔记

    最近因为业务需求,需要在两个数据库之间做双向实时同步,遂实践了一把Oracle的流复制,遇到了很多疑难问题,最终也貌似成功,现记录如下. 我是使用OEM来实现流复制的. 10.进行流复制的两个数据库的 ...

  5. Script 语言的简单练习题 乘法口诀

    <script>for(var i=1;i<=9;i++){ for(var k=1;k<=i;k++) { document.write(k+"x"+i+ ...

  6. BooleanToVisibilityConverter.cs

    //---------------------------------------------------------------------------- // // Copyright (C) M ...

  7. php入门

    最近公司招了几个应届毕业生,他们对前端的了解还挺多,但是对后端的技术一无所知,我觉得,作为一个前端攻城狮,如果你有远大的抱负,就应该雨露均沾... 今天我就跟大家讲一讲PHP最基本的入门,至少别人问起 ...

  8. HDU Machine scheduling

    Machine scheduling Time Limit : 5000/2000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) ...

  9. jQuery验证元素是否为空的两种常用方法

    这篇文章主要介绍了jQuery验证元素是否为空的两种常用方法,实例分析了两种常用的判断为空技巧,非常具有实用价值,需要的朋友可以参考下 本文实例讲述了jQuery验证元素是否为空的两种常用方法.分享给 ...

  10. 逻辑操作符---Lua: and,or,not 对比 C++:&&,||,!

    lua中有三个逻辑操作符:and,or,not(逻辑与,逻辑或,逻辑非),同样c++也有类似的三个逻辑操作符:&&,||,!(逻辑与,逻辑或,逻辑非).他们的运算对象就是真和假.lua ...