JVM的即时编译器JIT之简单介绍
注:本文源于《深入JAVA虚拟机》一书,提取部分骨干内容,算是读书笔记吧。
本文写于2011年11月
问题:
- 为何JVM需要使用解释器和编译器并存的架构?
- JVM为什么要实现两个不同的即时编译器?
- 程序何时会使用解释器执行?何时会使用编译器执行?
- 哪些程序代码会被编译成为本地代码?如何编译?
- JAVA代码的执行效率就一定比C,C++静态执行的执行差?JAVA代码解析执行有何优势?
序:
从计算机程序出现的第一天起,对效率的追逐就是程序天生的坚定的信仰,这个过程犹如一场没有终点,永不停歇的F1方程式竞赛。
程序员犹如车手,技术平台则是赛道上飞驰的赛车。
JVM即时编译器:即时编译器(Just In Time Compiler) 简称JIT
JAVA程序最初是通过解释器(Interpreter)进行解释执行的,当JVM发现某个方法或代码块运行特别频繁的时候,就会认为这是“热点代码”(Hot Spot Code)。
为了提高热点代码的执行效率,就会将这些“热点代码”编译成与本地机器相关的机器码,进行各个层次的优化。 完成这个任务的编译器就是即时编译器(JIT)。
即时编译器的性能好坏,代码的优化程度高低是衡量一款商用虚拟机优秀与否的最关键指标之一,它是虚拟机最核心最能体现技术水平的部分。
JVM的两款即时编译器JIT
JVM中默认内置了两款即时编译器,称为Client Compiler和Server Compiler。
可以用指定参数的方式,指定采用Client模式和Server模式。默认是mixed模式。
java –Xint 解析 java –Xcomp 编译
为什么解析器与编译器并存:
1、当程序需要迅速启动和执行的时候,解析器首先发挥作用,省去编译的时间,立即执行。随着时间的推移,编译器发挥作用,把越来越多的代码编译成本地代码,获得更高的执行效率。
2、当机器内存限制比较大,可以用解析方式节约内存,反之可以用编译提升效率。
3、解析器还可以作为编译器的“逃生门”。当例如加载了新类后类型结构发生变化,可以采用逆优化,退回到解析状态继续执行。
Client Compiler和Server Compiler
Client Compiler和Server Compiler会实现分层编译(JDK 1.7默认有)。
第0层 程序解析执行,解析器不开启性能监控,可触发第一层编译。
第1层 编译成本地相关代码,进行简单优化
第2层 除编译成本地相关代码外,还进行成编译耗时较长的优化。
Client Compiler获得更高的编译速度 Server Compiler获得更好的编译质量,无须承担性能监控的任务
热点代码
两类:1、多次被调用的方法
2、多次被执行的循环体
热点判定方式,两种:
1、基于采样的方式探测(Sample Based Hot Spot Detection) 。周期性检测各个线程的栈顶,发现某个方法经常出险在栈顶,就认为是热点方法。好处就是简单,缺点就是无法精确确认一个方法的热度。容易受线程阻塞或别的原因干扰热点探测。
2、基于计数器的热点探测(Counter Based Hot Spot Detection)。某个方法超过阀值就认为是热点方法,触发JIT编译。(涉及计数器的热度半衰减过程)
两个计数器:方法调用计数器(Invocation Counter)和回边计数器(Back Edge Counter)
触发了JIT编译,编译工作完成,这个方法的入口就会被系统自动改为新的编译入口,就会调用编译的版本。
JVM编译优化技术-----逃逸分析
JDK设计团队,几乎把所有的优化措施都集中在即时编译器中。一般认为,编译器的本地会比javac的产生的字节码更优秀。
常见的优化技术很多:例如公共表达式的消除,数组边界检查的消除,方法的内联(最重要的优化技术)
介绍一个JVM最前沿的优化技术:逃逸分析:
逃逸分析:当一个对象被定义后,可能被外部方法引用,例如被当作参数传递到其他方法中,称为方法逃逸。可以被其他线程访问,这个称为线程逃逸。
若能证明这个对象不会逃逸到其他方法或线程中,就可以进行高效的优化。
1、栈上分配 在堆上分配对象内存,回收整理内存需要消耗时间,若在栈上分配内存将是个不错的主意。被对象占用的空间就可以随帧栈的就出栈而销毁。大量的对象随方法的结束而自动销毁,GC也减轻压力。
2、同步消除 若不会线程逃逸,不会有竞争,方法上的同步措施就会消除。
3、标量替换 JAVA的原始类型无法再分就是一个标量,对象就是聚合量。对象若可以被拆分成标量,直接在栈上分配,就是类似栈上分配内存,甚至分配到高速缓存中。
逃逸分析不成熟的原因:不能保证逃逸分析的性能收益大于它的消耗。
Java与C/C++编译器对比
Java与C/C++编译器的对比,代表了最经典的即时编译器与静态编译器的对比。除了自身API的实现的好坏,更多是一场“拼编译器”和“拼输出代码质量”的游戏。
看看这两种语言的编译器的优劣:
1、即时编译器运行占用的是用户的运行时间,具有很大的时间压力,它提供的优化手段严重受制与编译的成本。而编译的时间在静态编译中并不是主要关注点。
2、java语言是动态的类型安全语言,意味着由虚拟机确保程序不会违反语言的语义或访问非结构化内存。虚拟机需要频繁的动态检查,如空指针,数组越界,继承关系等,总体消耗不少时间。
3、java语言使用虚方法的频率远大于C/C++,意味对方法的接收者进行多态的选择频率远大于C/C++,意味着即时编译器的优化难度远远大于C/C++编译器。
4、java语言是动态扩展的语言,运行时会加载新的类,改变程序的继承关系,使得很多全局优化难以进行。只能采用激进的方式,在运行时撤销或重新进行一些优化。
5、java语言的对象是在堆上分配,只有方法的局部变量才在栈上分配。而C/C++语言有多种分配方式,既可以在堆上分配,又可以在栈上分配,减轻了内存回收的压力。另外C/C++语言主要由用户代码回收内存,不存在无用对象筛选的过程,效率要比垃圾回收机制要高。
但是:
Java语言在性能上的劣势都是为了换取开发效率上的优势而付出的代价。动态安全,动态扩展,垃圾回收这些“拖后腿”的特性都是为JAVA的开发效率做出了很大的贡献。
何况java即时编译器能做的,C/C++的静态优化编译器不一定能够做:
由于C/C++的静态编译,以运行性能监控为基础的优化措施它都无法进行,如调用频率预测,分支频率预测,裁剪未使用分支等,这些都是称为java语言独有的性能优势。
相关推荐
21丨深入JVM即时编译器JIT,优化Java编译.html
说到编译,我猜你一定会想到 .java 文件被编译成 .class 文件的过程,这个编译我们一般称为...由于机器无法直接运行 Java 生成的字节码,所以在运行时,JIT 或解释器会将字节码转换成机器码,这个过程就叫运行时编译。
避免使用Java序列化14讲多线程之锁优化(下):使用乐观锁优化并行操作16讲多线程调优(下):如何优化多线程上下文切换17讲并发容器的使用:识别不同场景下最优容器21讲深入JVM即时编译器JIT,优化Java编译25讲答疑...
在服务器运行时期间,所有 JVM 都使用即时(JIT)编译器来将 Java 字节码编译为本机指令。 Java 内存或堆调整。JVM 内存管理功能(即垃圾回收)为提高 JVM 性能提供了其中一种最大的可能性。 类装入调整。 过程 ...
Java虚拟机(Java Virtual Machine,简称JVM),Java的“一处编译,处处运行...作用:用于存放已被加载的类信息、常量、静态变量、即时编译器(JIT)编译后的代码等数据。 所有线程共享方法区。 方法区内存可以动态扩展,动
JiT:即时编译 两大无关性 平台无关性: 每一台平台解释器不同,但是虚拟机相同,跨平台的原因。 一个程序对应一个虚拟机,多个程序对应多个虚拟机, 虚拟机之间数据不共享 什么是平台:操作系统及其硬件环境。跨...
├─(3) 0803_【掌握】JIT即时编译器.mp4 ├─(4) 0804_【掌握】JVM堆内存结构.mp4 ├─(5) 0805_【掌握】新生代内存管理.mp4 ├─(6) 0806_【掌握】老年代内存管理.mp4 ├─(7) 0807_【掌握】元空间.mp4 ├─(8) ...
(1)解析:.class文件经过JVM内嵌的解析器解析执行 (2)编译:存在JIT编译器(Just In Time Compile 即时编译器)把经常运行的代码
JIT(java即时编译器) 前者是用 PC计数器 来依次编译每一行代码解释为本地机器指令; 后者是通过 寻找热点代码 进行即时编译为本地机器指令; GC: 垃圾回收器 主要的三款商用虚拟机JVM: 1) HotSpot JVM 特点: 热点...
到目前为止,GraalVM提供了两种运行Java程序的方法:将Java HotSpot VM与GraalVM JIT(即时)编译器一起使用,以及第二种方法:使用GraalVM Native Image编译为本机可执行文件。 今天,我们很高兴地宣布一种在...
mvnd -Maven守护程序 目录 介绍 该项目旨在使用Gradle和Takari已知的技术提供更快的构建。 架构概述: ... JVM内的即时(JIT)编译器生成的本机代码也将保留。 与股票Maven相比,JIT编译花费的时
讲解了虚拟机的热点探测方法、HotSpot的即时编译器、编译触发条件,以及如何从虚拟机外部观察和分析JIT编译的数据和结果;第五部分探讨了Java实现高效并发的原理,包括JVM内存模型的结构和操作;原子性、可见性和...