深入理解JVM之前端编译器(一)
前两天在leetcode做了算法题,惊讶的发现用java实现的时间复杂度,竟然跻身于C/C++同列,甚至偶尔会超过后两者,虽然知道JVM功不可没,但还是很好奇在VM编译过程中到底发生了什么,翻出《深入理解java虚拟机》一探究竟,算是有所收获,记录如下。
概述
java语言的“编译期”其实是一段“不确定”的操作过程,因为可能是下面三种:
- 前端编译器
叫编译器的前端可能更合适,主要是把.java文件转变成.class文件。主要种类有:Sun的Javac、Eclipse JDT的增量式编译器(ECJ)。 - JIT编译器
就是可能指虚拟机的后端运行期编译器(JIT编译器:Just In Time Compiler),把「字节码」变成「机器码」,主要有:Hotspot VM的C1、C2编译器。 - AOT编译器
上面两个可能关心更多,这个是指用静态提前编译器(AOT编译器:Ahead Of Time Compiler)直接把*.java变成本地机器码的过程。
本文后面所指的编译器和编译期都表示第一种。
关于优化的两点解释:
- Javac这类编译器对代码的运行效率几乎没有任何优化措施。只是做了一些针对java语言「编码过程」的“优化”措施来改善程序员的「编码风格和编码效率」(俗称“语法糖”,并没有涉及虚拟机底层的改进)。
- 虚拟机设计团队把对性能的优化集中到了后端的即时编译中,这样可以让那些不是有javac产生的Class文件(如JRuby、Groovy等语言的Class)也同样能享受到编译器优化所带来的好处。
也就是说java中即时编译器的在运行期的优化对程序运行更重要,而前端编译器在编译期的优化对于程序编码更重要。注意此处的「编译期」和「运行期」、「程序编码」和「程序运行」的区别。
Javac编译器
Javac不像是Hotspot虚拟机本身是CPP(少量C)写的,本身是java语言编写的程序,这样java程序员就很方便了解它的编译过程了。关于源码环境搭建和调试不做详述,大致说下Javac的编译过程,主要分为3个过程,分别是:
- 解析与填充符号表过程
- 插入式注解处理器的注解处理过程
- 分析与字节码生成过程
Java语法糖
语法糖虽不能带来实质性的功能的改进,但是它们或能提高效率,或能提升语法严谨性,或能减少编码出错机会。java中常见的语法糖如下:
泛型与泛型擦除
java的泛型规则只在程序源码中存在,在编译后就已经替换为原来的原生类型(RawType,裸类型),并且在相应的地方插入了强制转换。
自动装箱、拆箱与遍历循环、变长参数
演示代码如下(以下jdk环境1.8):
1 2 3 4 5 6 7 8 9 10 11 |
public class AutoBoxCompile { public static void main(String[] args) { List<Integer> list =Arrays.asList(1,2,3,4); int sum=0; for (Integer i : list) { sum+=i; } System.out.println(sum); } } |
用的本地jd-gui.exe工具反编译之后变成:
1 2 3 4 5 6 7 8 9 10 11 12 |
public class AutoBoxCompile { public static void main(String[] args) { List list = Arrays.asList(new Integer[] { Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3), Integer.valueOf(4) }); int sum = 0; for (Integer i : list) { sum += i.intValue(); } System.out.println(sum); } } |
foreach明明是一颗语法糖特性,猜想是工具的问题,找了一个在线反编译工具,得到下列代码,可以发现变长参数、自动装箱和遍历循环的语法糖特性:
条件编译
类似于下面这段if代码,在编译过程中就会被“运行”。
1 2 3 4 5 6 7 8 9 |
public class Ifcompiler { public static void main(String[] args) { if (true) { System.out.println(1111); }else { System.out.println(2222); } } } |
生成的字节码只包括System.out.println(1111);,将上述编译之后产生的class反编译如下图:
只有使用条件为常量的if语句才能有上述效果,否则会被拒绝编译比如while(false){};。
还有很多其他的语法糖,比如内部类、枚举、断言、switch以及try中关闭资源等等,有时间再去尝试,重要的是明白语法糖是怎么回事。
最后
「之所以把从java文件到字节码文件的编译器叫做前段编译器,是因为它只完成了从程序到抽象语法树或者中间字节码的转变,而在此之后还有一组内置于虚拟机内部的“后端编译器”完成了从字节码到本地机器码的过程,即前面提到的即时编译器或JIT编译器,这个编译器的编译速度及结果的优劣,是衡量虚拟机性能的很重要的指标。」
JVM还有很多的东西没有去挖掘,希望这是个开端,能不断的去探索java虚拟机更深处的东西。
from:http://zouzls.github.io/2016/09/06/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3JVM%E4%B9%8B%E5%89%8D%E7%AB%AF%E7%BC%96%E8%AF%91%E5%99%A8%EF%BC%88%E4%B8%80%EF%BC%89/
深入理解JVM之前端编译器(一)相关推荐
- 深入理解JVM之JIT编译器(二)
上篇是分析了一下前段编译器,主要过程完成从java代码到字节码的转变,它的改进顶多是提高程序的编码速度和效率.本篇尝试探索JIT编译器,它能够完成从字节码到本地机器码的转变,从而真正的影响程序的运行效 ...
- 深入理解JVM虚拟机(八):编译器优化
本博客从编译期源码实现的层次上让我们了解了Java源代码编译为字节码的过程,分析了Java语言中泛型.主动装箱/拆箱.条件编译等多种语法糖的前因后果. 1. 概述 java语言的"编译期&q ...
- 《深入理解JVM 第三版》 读书笔记
2 Java内存区域与内存溢出异常 2.2 运行时数据区域 2.2.1程序计数器 程序计数器占用空间较小,可以看作当前 线程执行字节码的行号.因此是线程独立的. 如果执行的是native方法,则该计数 ...
- 深入理解JVM内存模型
博客园 首页 新随笔 联系 管理 订阅 随笔- 323 文章- 0 评论- 40 深入理解JVM-JVM内存模型 我们知道,计算机CPU和内存的交互是最频繁的,内存是我们的高速缓存区,用户磁盘和 ...
- [译]深入理解JVM
深入理解JVM 原文链接:http://www.cubrid.org/blog/dev-platform/understanding-jvm-internals 每个使用Java的开发者都知道Java ...
- 一文带你深入理解JVM内存模型
一文带你深入理解JVM内存模型 一.JAVA的并发模型 共享内存模型 在共享内存的并发模型里面,线程之间共享程序的公共状态,线程之间通过读写内存中公共状态来进行隐式通信 该内存指的是主内存,实际上是物 ...
- 深入理解 JVM Class文件格式(十)
到此, 所有关于class文件格式的重要内容都已经讲解完了, 不敢说面面俱到, 但是敢说大部分重要的内容都包含在内了.前前后后用了9篇博客来专门讲解class文件结构, 为什么花那么多的时间和精力来介 ...
- 深入理解 JVM Class文件格式(九)
经过前八篇关于class文件的博客, 关于class文件格式的内容也基本上讲完了. 本文是关于class文件格式的最后一篇. 在这篇博客中, 将会讲解关于方法的几个属性. 理解这篇博客的内容, 对于理 ...
- 深入理解 JVM Class文件格式(八)
在本专栏的第一篇文章 深入理解Java虚拟机到底是什么 中, 我们主要讲解了什么是虚拟机, 这篇博客是对JVM的一个概述. 在随后的几篇文章中,一直在讲解class文件格式. 在今天这篇博客中, 将会 ...
最新文章
- 94年出生,如今985高校博士生导师!
- R语言ggplot2可视化删除所有分面图(facet_wrap可视化的facet结果)的标签实战(Remove facet_wrap labels)
- UVA11732 strcmp() Anyone?
- 发布 SharePoint Server 2007 Starter Page
- BZOJ 3993 Luogu P3324 [SDOI2015]星际战争 (最大流、二分答案)
- VTK:vtkCompositePolyDataMapper2用法实战
- iOS,Objective-C Runtime
- OPenGL实例化绘制、普通绘制说明
- Oracle数据库用法汇总
- 数据结构与算法笔记(五) 链表的应用
- MYSQL的索引类型:PRIMARY, INDEX,UNIQUE,FULLTEXT,SPAIAL 区别与使用场合
- 【项目篇】Android团队项目开发之统一代码规范
- CPU 和 GPU 的区别
- echars 绘制多点连线地图 vue
- 昆仑通态屏幕制作(连载5)---基础篇(串口接收,文本与灯显示)
- CST2018/2020安装注意事项
- C51最小系统板红外遥控控制led灯的亮灭
- 亚马逊热销爆款产品货源有哪些?亚马逊无货源怎么做?
- b站网页html,bilibili注册页面html简单分析
- Linux C/C++编程:netstat分析tcp状态转移(socket通信)