六 早期(编译期)优化
 
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. sqlserver2008简介

    sql 数据库简介 应该掌握的部分: 1.  数据库的基本概念 2.  数据库模型的基本概念 3.  实体联系模型的基本概念 4.  关系模型的基本概念和性质 5.  数据库优化理论 6.  掌握创建 ...

  2. 关于 lua table表存储函数且运用

    --table 是lua的一种数据结构用来帮助我们创建不同的数据类型.如:数组和字典--lua table 使用关联型数组,你可以用任意类型的值来做数组的索引,但这个值不能是nil--lua tabl ...

  3. Nginx failing to load CSS and JS files (MIME type error)

    Nginx failing to load CSS and JS files (MIME type error) Nginx加载静态文件失败的解决方法(MIME type错误) 上线新的页面,需要在n ...

  4. 18.24 Ubuntu修改静态IP

    1.查询系统当前的ip地址配置信息,输入ifconfig命令进行查看 2.打开文件设置静态IP sudo vi /etc/network/interfaces 3.设置address ip.gatew ...

  5. C#中使用EntityFramework(EF)生成实体进行存储过程的调用

    在EF中使用定义对象模型的方式调用一个存储过程,这个存储过程返回的是一组包含两列的值.(ProjectName,Count) 下面是存储过程: CREATE procedure [dbo].[Pro_ ...

  6. Git 日常操作

    本地新建Git库步骤: 初始化git库:git init 建立本地和远程的关联: git remote add origin ip:端口/ 项目.git 从远程下载所有分支到本地:git  fetch ...

  7. aspnetcore2.1 部署到docker (访问出现404)

    Dockerfile FROM microsoft/dotnet:2.1-aspnetcore-runtime WORKDIR /app COPY ./publish . ENTRYPOINT [&q ...

  8. vivado源文件和仿真文件的建立

    目的:做一个3输入,1输出模块:其中只要有2个输入为1则输出为1: 1.打开vivado创建一个工程 2.选择保存路径和名称 3.选择创建rtl文件且勾选下面的选项 4.选择芯片如xc7a35tift ...

  9. win10 vs2015源码编译tesseract4.0

    1.安装软件 cmake  下载地址 cppan   下载地址 安装完毕后,需要将cmake.exe和cppan.exe加入环境变量PATH中 cmake简介 CMake全称为“cross platf ...

  10. cplusplus标准库

    http://www.cplusplus.com/reference/   Standard C++ Library reference C Library The elements of the C ...