早期(编译期)优化

一、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. Microsoft JScript提示‘DIRECT’未定义(2014-08-26记)

    当启动Applet的时候,页面弹出:DIRECT’未定义可能的问题是:java控制面板的网络设置问题,可能使用了代理解决: 打开java控制面板--->网络设置-->直接连接-->确 ...

  2. Dynamics AX 2012 R3 Demo 安装与配置 - 编译和配置 (Step 3)

        在前两节中,Reinhard主要讲解了如何配置安装环境,安装数据库服务器,AOS和客户端.至此安装工作已经结束,下面Reinhard开始讲解如何编译和配置.     运行客户端后,系统弹出初始 ...

  3. 一、Docker之旅

    刚刚接触到docker的同事可能会一头雾水,docker到底是一个什么东西,先看看官方的定义. Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的.可移植的.自给自足的容器.开发者在笔 ...

  4. java转换unicode,筛选文件中的insert语句并把日期给转换为可以直接在数据库执行的语句

    package com; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; impo ...

  5. noi 8787 数的划分

    题目链接:http://noi.openjudge.cn/ch0206/8787/ 将整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序). 简直跟分苹果一模一样. #include < ...

  6. Linux 2.6内核Makefile浅析

    1 概述 Makefile由五个部分组成: Makefile:根目录Makefile,它读取.config文件,并负责创建vmlinux(内核镜像)和modules(模块文件). .config:内核 ...

  7. 【MySQL】MySQL快速插入大量数据

    起源 在公司优化SQL遇到一个索引的问题,晚上回家想继续验证,无奈没有较多数据的表,于是,想造一些随机的数据,用于验证. 于是 于是动手写.由于自己不是MySQL能手,写得也不好.最后,插入的速度也不 ...

  8. 使用phantomjs操作DOM并对页面进行截图需要注意的几个问题

    phantomjs是一个无界面浏览器,可用于网页截图和前端自动化测试,基于webkit内核(也就是chrome使用的内核),并使用js编写业务脚本来请求.浏览和操作页面.最近前端监控需要用到phant ...

  9. [jetbrains系列] 外链第三方库+代码补全设置

    jetbrains系列的IDE真的是太好用了,有种相见恨晚的感觉. 在开发过程中第三方库是必不可少的,在开发的时候如果有一个可以补全的IDE可以节省查文档的时间. 举个例子:给pycharm配pysp ...

  10. 查看数据源所对应的PSA物理表

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...