六 早期(编译期)优化
 
1 “编译期”的含义
    · 可能是指一个前端编译器把*.java文件转变成*.class文件的过程,前端编译器如:Sun的Javac、Eclipse JDT中的增量式编译器(ECJ);
    · 也可能是指虚拟机的后端运行期编译器(JIT编译器)把字节码转变成机器码的过程,JIT编译器如:HotSpot VM的C1、C2编译器;
    · 还可能是指使用静态提前编译器(AOT编译器)直接把*.java文件编译成本地机器码的过程,AOT编译器如:GNU Compiler for the Java(GCJ)、Excelsior JET。
    本部分的编译期指第一种。
    前端编译器在编译期的优化与程序编码关系更加密切,JIT编译器在运行期的优化对程序运行来说更加重要。
 
2 Javac编译器
        ---Javac编译器是一个使用Java语言编写的程序。
        ---编译过程大致可以分为:
            · 解析与填充符号表过程;
            · 插入式注解处理器的注解处理过程;
            · 分析与字节码生成过程。
        ---这三个步骤之间的关系与交互顺序如下图:
                
(1)解析与填充符号表
        1)词法分析和语法分析
                ---词法分析:将源代码的字符流转变成标记(Token)集合。
                ---单个字符是程序编写过程的最小元素,标记是编译过程的最小元素。
                ---标记包括:关键字、变量名、字面量、运算符。
                ---语法分析:根据标记序列构造抽象语法树的过程。
                ---抽象语法树:一种用来描述程序代码语法结构的树形表示方式。语法树的每一个节点都代表着程序代码中的一个语法结构,如包、类型、修饰符、运算符、接口、返回值、代码注释等。
        2)填充符号表
                ---符号表:由一组符号地址和符号信息构成的表格。
                ---符号表中所登记的信息在编译的不同阶段都要用到。在语义分析中,符号表所登记的内容将用于语义检查和产生中间代码;在目标代码生成阶段,当对符号名进行地址分配时,符号表是地址分配的依据。
    (2)注解处理器
            ---在编译期间对注解进行处理,可以读取、修改、添加抽象语法树中的任意元素。若在处理注解期间对语法树进行了修改,编译器将回到解析及填充符号表的过程重新处理,直到所有插入式注解处理器都没有再对语法树进行修改为止。
    (3)语义分析和字节码生成
            ---语义分析:对结构上正确的源程序进行上下文性质的审查,如进行类型审查。
            ---语义分析包括:标注检查和数据及控制流分析两步。
            1)标注检查
                    ---检查的内容包括如变量使用前是否已经被声明、变量与赋值之间的数据类型是否能够匹配、常量折叠等
            2)数据及控制流分析
                    ---是对程序上下文逻辑更进一步的验证,可以检查出诸如程序局部变量在使用前是否有赋值、方法的每条路径是否都有返回值、是否所有的受查异常都别正确处理了等问题。
            3)解语法糖
                    ---Java中常用的语法糖:泛型、变长参数、自动装箱/拆箱、遍历循环、条件编译、内部类、枚举类、断言语句、对枚举和字符串的switch支持、try语句中定义和关闭资源等。
                    ---解语法糖:虚拟机运行时不支持语法糖的语法,它们在编译阶段被还原回简单的基础语法结构。
            4)字节码生成
                    ---不仅仅把前面各个步骤所生成的信息转换成字节码写到磁盘中,编译器还进行了少量的代码添加和转换工作。
                    ---实例构造器<init>()方法和类构造器<clinit>()方法就是在这个阶段添加到语法树之中的。这里的实例构造器不包括默认构造函数,默认构造函数是在填充符号表阶段添加完成的。
                    ---<init>()方法和<clinit>()方法实际上是一个代码收敛的过程,编译器会把语句块({}块或static{}块)、变量初始化(实例变量和类变量)、调用父类的实例构造器(<clinit>()方法中无须调用父类的<clinit>()方法)等操作收敛到<init>()方法和<clinit>()方法中。
                    ---代码替换例子:把字符串的加操作替换成StringBuffer或StringBuilder(取决于JDK版本是否大于等于JDK1.5)的append()操作。
 
3 Java语法糖
    (1)泛型与类型擦除
            ---真实泛型:泛型无论在程序源码中、编译后的中间代码中,还是运行期的代码中,都是切实存在的,这种实现称为类型膨胀,基于这种方法实现的泛型称为真实泛型。
            ---伪泛型:只在程序源码中存在,在编译后的字节码文件中就已经替换为原生类型了,并且在相应的地方插入了强制转型代码,这种实现称为类型擦除,基于这种方法实现的泛型称为伪泛型。
            ---Signature属性存储了一个方法在字节码层面的特征签名,这个属性中保存的参数类型并不是原生类型,而是包括了参数化类型的信息。
            ---擦除法所谓的擦除,仅仅是对方法的Code属性中的字节码进行擦除,实际上元数据中还是保留了泛型信息(在Signature属性中),这也是我们能通过反射手段取得参数化类型的根本依据。
    (2)自动装箱、拆箱、遍历循环与变长参数
                ---遍历循环需要被遍历的类实现Iterable接口的原因:遍历循环在编译之后会还原成迭代器的实现。
                ---变长参数在编译后会还原成数组实现。
                ---自动拆、装箱的陷阱:
                    · 当两个包装类进行比较时,包装类的“==”运算在不遇到算术运算的情况下不会自动拆箱;
                    · 当两个包装类进行比较或一个包装类与另一个基本数据进行比较时,它们的equals()方法不会处理数据转型的关系;
                    · 当一个包装类与一个基本数据类型进行比较或两个基本数据类型进行比较时,"=="运算会自动拆箱、自动类型转换;
                    · 对于Integer类,当值在-128-127之间时,会使用Integer.valueOf()方法直接从缓存中取出相应对象;而当值不在这个范围内时,会使用Integer.valueOf()方法new一个Integer对象。
                ---程序代码为:
                        
                    ---执行结果为:
                            
    (3)条件编译
            ---只能使用条件为常量的if语句才能实现,如果使用常量与其他带有条件判断能力的语句搭配,则可能在控制流分析中提示错误,被拒绝编译。
                    

深入理解Java虚拟机读书笔记6----早期(编译期)优化的更多相关文章

  1. 深入理解Java虚拟机 -- 读书笔记(1):JVM运行时数据区域

    深入理解Java虚拟机 -- 读书笔记:JVM运行时数据区域 本文转载:http://blog.csdn.net/jubincn/article/details/8607790 本系列为<深入理 ...

  2. 【Todo】深入理解Java虚拟机 读书笔记

    有一个在线系列地址 <深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)> http://book.2cto.com/201306/25426.html 已经下载了这本书(60多M ...

  3. 深入理解Java虚拟机读书笔记5----虚拟机字节码执行引擎

    五 虚拟机字节码执行引擎   1 运行时栈帧结构     ---栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构,是虚拟机运行时数据区中的虚拟机栈的栈元素.     ---栈帧中存储了方法的局部变 ...

  4. 深入理解Java虚拟机读书笔记8----Java内存模型与线程

    八 Java内存模型与线程   1 Java内存模型     ---主要目标:定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节.     ---此处的变量和J ...

  5. 深入理解Java虚拟机读书笔记7----晚期(运行期)优化

    七 晚期(运行期)优化 1 即时编译器(JIT编译器)     ---当虚拟机发现某个方法或代码块的运行特别频繁时,就会把这些代码认定为“热点代码”,包括被多次调用的方法和被多次执行的循环体.     ...

  6. 深入理解Java虚拟机读书笔记4----虚拟机类加载机制

    四 虚拟机类加载机制 1 类加载机制     ---概念:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型.     -- ...

  7. 深入理解Java虚拟机读书笔记3----类文件结构

    三 类文件结构 1 Java虚拟机的两种中立特性     · 平台无关性     · 语言无关性     实现平台无关性和语言无关性的基础是虚拟机和字节码存储格式(Class文件).   2 Clas ...

  8. 深入理解Java虚拟机读书笔记1----Java内存区域与HotSpot虚拟机对象

    一 Java内存区域与HotSpot虚拟机对象 1 Java技术体系.JDK.JRE?     Java技术体系包括:         · Java程序设计语言:         · 各种硬件平台上的 ...

  9. 深入理解java虚拟机读书笔记--java内存区域和管理

    第二章:Java内存区域和内存溢出异常 2.2运行时数据区域 运行时数据区分为方法区,堆,虚拟机栈,本地方法栈,程序计数器 方法区和堆是线程共享的区域 虚拟机栈,本地方法栈,程序计数器是数据隔离的数据 ...

随机推荐

  1. UE4 PostProcessVolume 蓝图操作后期框

    如图找到场景里面的后期框,首先我们要获得它的设置,Settings 大概就是属性的意思.通过Settings设置其它的属性.Set members in PostProcessSetting 就是接口 ...

  2. 使用docker构建简约高效的镜像

    背景介绍 最近在思考一个问题,我的golang运行到docker环境上的时候,需要安装很大依赖.思考发现我需要就是一个运行二进制的环境而已并不需要golang的编译器等等其他任何多余的. 当前的doc ...

  3. centos tree 命令

    ftp://mama.indstate.edu/linux/tree/ download & make

  4. ANSYS分析中的单位

    ANSYS输入的数值的单位换算比较复杂,参数的单位需要自己进行定义. 不同单位对应课件文件

  5. tomcat使用自签名证书实现https加密访问

    部署好java环境和tomcat之后 执行以下语句 #生成证书,keytool是java工具命令,-genkey生成证书,-alias证书名称,-keyalg应该是指算法,-keystore是证书存储 ...

  6. Java 异常: SimpleDateFormat java.lang.NumberFormatException: multiple points

    Java  SimpleDateFormat 是不支持多线程的.在不同线程同时用 一个 SimpleDateFormat  实例对象做日期装换,或抛出上面的 2 种 异常,所以 用到 SimpleDa ...

  7. httpd日志格式

    日志的缺省格式有如下几种: LogFormat "%h %l %u %t "%r" %>s %b "%{Referer}i" "%{U ...

  8. postfix配置&使用

    myorigin = $mydomain #以“user@example.com”(而不是“user@hostname.example.com”)发送邮件, #这样就没有理由将邮件发送到“user@h ...

  9. bat文件与Vbs文件常用操作(获取用户输入,执行VBS文件)

    bat文件: set /P StrInput="输入数字:" echo 输入的数字为%StrInput% set /P Flg="是否执行(y/n):" IF ...

  10. [转]Windows 经验集

    Windows Server 2012 R2 显示 这台电脑 图标方法: 来自:https://jingyan.baidu.com/article/f25ef2544f6883482c1b82e5.h ...