六 早期(编译期)优化
 
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. 关于mysql中存储json数据的读取问题

    在mysql中存储json数据,字段类型用text,java实体中用String接受. 返回前端时(我这里返回前端的是一个map),为了保证读取出的数据排序错乱问题,定义Map时要用LinkedHas ...

  2. selenium_Python3_邮箱登录:动态元素定位

    这里的关键是动态frame定位: 其他元素定位不用多说,常规操作. 不过需要注意加上这个: from selenium.webdriver.remote.webelement import WebEl ...

  3. bugku 密码学一些题的wp

    ---恢复内容开始--- 1.滴答滴 摩斯密码,http://tool.bugku.com/mosi/ 2.聪明的小羊 从提示猜是栅栏密码,http://tool.bugku.com/jiemi/ 3 ...

  4. Redis不支持ssl

    一直在公司内部推荐redis做cache管理,今天偶然想起虽然C#没问题,可是c/c++没查过可不可行. 结果查了一下,还真tmd有问题,官方的c client版本只支持linux side的,根本没 ...

  5. 【模板】字符串匹配的三种做法(Hash、KMP、STL)

    题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 输入输出格式 输入格式: 第一行为一个字符串,即为s1 第二行为一个字符串,即为s2 输出格式: 1行 ...

  6. c# 坑人的发邮件组件

    System.Net.Mail 在服务器25端口被封禁的情况下,无法使用其它诸如SSL 465端口发送.用过时的System.Web.Mail却可以.是微软更新速度太快呢,还是标准不一致呢. Syst ...

  7. JNI加载hal的dlopen()相关操作

    1.函数集合 #include <dlfcn.h> void *dlopen(const char *filename, int flag); char *dlerror(void); v ...

  8. 多线程之BlockingQueue中 take、offer、put、add的一些比较

    一.概述: BlockingQueue作为线程容器,可以为线程同步提供有力的保障.   二.BlockingQueue定义的常用方法 1.BlockingQueue定义的常用方法如下:   抛出异常 ...

  9. 剑指offer 12.代码的完整性 数值的整数次方

    题目描述 给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方.   本人渣渣代码: public double Power(double ba ...

  10. Hbase数据库

        1.简介 HBase从诞生至今将近10年,在apache基金会的孵化下,已经变成一个非常成熟的项目,也有许多不同的公司支持着许多不同的分支版本,如cloudra等等. HBase不同于一般的关 ...