JVM原理:4 运行期优化
JVM运行期优化
Java程序在运行的期间,可能会有某个方法或者代码块的运行特别频繁时,就会把这些代码认定为“热点代码”。为了提高热点代码的执行效率,在运行时JVM会将这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个任务的编译器称为即时编译器(Just In Time Compiler,JIT编译器)。
即时编译器(JIT)
事实上,现在许多主流的商用虚拟机,都同时包含有解释器与编译器,解释器与编译器两者各有优势。与解释器相比,编译器会将常运行到的代码编译成本地代码区实现,可以获取更高的执行效率。而当程序运行环境中内存资源限制较大时,可以使用解释执行节约内存,反之可以使用编译执行来提高效率。解释器和编译器之间还可以通过逆优化退回到解释状态继续执行,因此,在整个虚拟机执行架构中,解释器与编译器经常配合工作。
HotSpot编译器中出现两个编译器Client Compiler称为C1编译器,Server Compiler称为C2编译器。JVM默认采用解释器与其中一个编译器直接配合的方法工作,程序使用哪个编译器,取决于虚拟机运行的模式,HotSpot虚拟机会根据自身版本与宿主机器的硬件性能自动选择运行模式,用户也可以使用“-client”或“server”参数去强制指定虚拟机运行在Client模式还是Server模式。
解释器与编译器搭配使用的方式在虚拟机中称为“混合模式”,用户可以使用参数”-Xint”强制虚拟机运行于解释模式,也可以使用“-Xcomp”强制虚拟机运行于编译模式。
为了在程序启动响应速度与运行效率之间达到最佳平衡,HotSpot虚拟机还会逐渐启动分层编译的策略,分层编译的概念在JDK1.6中出现,后来一直处于改进阶段,最终在JDK1.7的Server模式虚拟机中作为umoren编译策略被开启。分层编译根据编译器编译、优化的规模与耗时,划分出不同的编译层次,其中包括:
- 第0层,程序解释执行,解释器不开启性能监控功能,可触发第1层编译。
- 第1层,也成为C1编译,将字节码编译为本地代码,进行简单、可靠的优化,如有必要时将加入性能监控的逻辑。
- 第2层(或2层以上):也成为C2编译,也是将字节码编译为本地代码,但是会启动一些编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化。
事实上,用Client Compiler获取更高的编译速度,用Server Compiler来获取更好的编译质量,在解释执行的时候也无须再承担收集性能监控信息的任务。
编译对象与触发条件
编译对象
在运行过程中会被即时编译器编译的“热点代码”有两类:
1、被多次调用的方法;
2、被多次执行的循环体。
对于第一种情况,由于是由方法调用触发的编译,因此编译器会以整个方法作为编译对象,这种编译也是虚拟机中标准的JIT编译方式。而对第二种情况,尽管编译动作是由循环体所触发的,但编译器依然会以整个方法作为编译对象,这种编译方式因为编译发生在方法执行过程之中,因此形象地被称为栈上替换,简称为OSR编译,即方法栈帧还在栈上,方法就被替换了。
触发条件
在这里提一个问题,被多次调用,在这里的多次具体是多少次?并且虚拟机如何统计一个方法或一段代码被执行过多少次?
判断一段代码是不是为热点代码,是不是需要触发即时编译,这样的行为称为热点探测,但进行热点探测也是不一定要知道方法具体被调用了多少次,目前主要的热点探 测判定方法有两种:
- 基于采样的热点探测:虚拟机会周期性地检查各种线程的栈顶,如果发现某个或者某些方法经常出现在栈顶,那这个方法就是“热点方法”。
优点:实现简单、高效,还可以很容易地获取方法调用方法。
缺点:很难精确地确认一个方法的热度,容易因为受到线程阻塞或别的外界因素的影响而扰乱热点探测。 - 基于计数器的热点探测:虚拟机会为每个方法尽力计数器,统计方法的执行次数,如果执行次数超过一定的阙值就认为它是热点方法。
优点:统计结构相对来说更加精确与严谨。
缺点:实现起来麻烦,需要为每个方法及建立并维护计数器,而且不能直接获取到方法的调用关系。
在HotSpot中使用的是第二种方法,基于计数器的热点探测法,因此它为每个方法准备了两类计数器:方法调用计数器和汇编计数器(统计一个方法中循环体代码执行的次数,在字节码中中遇到控制流向后跳转的指令称为“回边”。建立回边计数器的目的是为了触发OSR编译。)。
编译过程:
在默认设置下,无论是方法调用产生即使编译请求,还是OSR编译请求,虚拟机在代码编译器还未完成之前,都仍然将按照解释方式继续执行,而编译动作则在后台的编译线程中进行。
在后台执行编译的过程中,编译器做了什么?Server Compiler和Client Compiler两个编译器的编译过程是不同的,对于Client Compiler来说,它是一个简单快速的三段式编译器,主要的关注点在于局部性的优化,而 放弃了许多耗时较长的全局优化手段。
1、一个平台独立前段将字节码构造成一种高级中间代码表示(HIR),HIR使用 静态单分配的形式来表示代码值,这可以使得一些在JIR的构造过程之中和之后进行的优化动作更容易实现。在此之前,编译器会在字节码上完成一部分基础优化,如方法内联、常量传播等。
2、一个平台相关的后端从HIR中产生低级中间代码表示,而在此之前,在HIR上完成另外一些优化, 如空值检查消除、范围检查消除等。
3、在平台的后端使用线性扫描算法在LIR上分配寄存器,并在LIR上做窥孔优化,然后产生机器代码。
对于Server Compiler则是专门面向服务端的典型应用并为服务端的性能配置特别调整过的编译期,也是一个充分优化过的高级编译器,它会执行所有经典的优化动作。
Server Compiler的寄存器分配器是一个全局图着色分配器,它可以充分利用某些处理器架构上的大寄存器集合。所以它也是比较缓慢的,但是编译代码质量高,可以减少本地代码的执行时间,从而抵消了额外的编译时间开销,所以很多非服务端的应用选择使用server模式的虚拟机运行。
编译优化技术
虚拟机中的具有代表性的优化技术:
语言无关的经典优化技术之一:公共子表达式消除。
语言相关的经典优化技术之一:数组范围检查消除。
最重要的优化技术之一:方法内联
最前沿的优化技术之一:逃逸分析
公共子表达式消除
如果一个表达式E已经计算过了,并且从先前的计算到现在E中所有变量的值都没有发生变化,那E的这次出现就成公共子表达式,可以用原先的表达式进行消除。数组边界检查消除
系统将自动进行上下界的范围检查。
隐式异常处理:Java中空指针和算术运算中除数为零的检查。此外还有:自动装箱消除、安全点消除、消除反射等等。方法内联
把目标方法的代码“复制”到发起调用的方法之中,避免发生真实的方法调用。逃逸分析
分析对象的动态作用域,当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递给其他方法,称为方法逃逸。甚至还有可能被外部线程访问到,比如赋值给类变量或可以在其他线程中访问到的实例变量,称为线程逃逸。
如果能证明一个对象不会逃逸到方法或线程之外,也就是别的方法或线程无法通过任何途径访问到这个对象,就可以为这个变量进行一些高效的优化:如:栈上分配、同步消除、标量替换等。
JVM原理:4 运行期优化的更多相关文章
- jvm虚拟机笔记<六> 运行期优化
这节我们总结一下JVM运行期的优化问题. https://www.cnblogs.com/zhouyuqin/p/5224573.html JVM运行期优化 即时编译器(JIT) 编译对象与触发条件 ...
- 深入了解JVM虚拟机8:Java的编译期优化与运行期优化
java编译期优化 java语言的编译期其实是一段不确定的操作过程,因为它可以分为三类编译过程:1.前端编译:把.java文件转变为.class文件2.后端编译:把字节码转变为机器码3.静态提前编译: ...
- 【深入理解JAVA虚拟机】第4部分.程序编译与代码优化.2.运行期优化。这章提到的具体的优化技术,应该对以后做性能工作会有帮助。
1.概述 Java程序最初是通过解释器(Interpreter)进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁时,就会把这些代码认定为“热点代码”(Hot Spot Code). 为了提高 ...
- 深入理解JVM - 晚期(运行期)优化
在部分商用虚拟机中,Java程序最初是通过解释器(Interpreter)进行解释执行的,当虚拟机发现某个方法或者代码块的运行特别频繁时,就会把这些代码认定为“热点代码”(Hot Spot Code) ...
- Java虚拟机11:运行期优化
前言 http://www.cnblogs.com/xrq730/p/4839245.html,HotSpot采用的是解释器+编译器并存的架构,之前的这篇文章里面已经讲过了,本文只是把即时编译器这块再 ...
- Java虚拟机15:运行期优化
前言 HotSpot采用的是解释器+编译器并存的架构,之前的这篇文章里面已经讲过了,本文只是把即时编译器这块再讲得具体一点而已.当然,其实本文的内容也没多大意义,90%都是概念上的东西,对于实际开发. ...
- 运行期优化 Java内存模型与线程 线程安全与优化
- JVM总结(六):晚期(运行期)优化
这节我们总结一下JVM运行期的优化问题. JVM运行期优化 即时编译器(JIT) 编译对象与触发条件 编译对象 触发条件 编译过程 编译优化技术 JVM运行期优化 Java程序在运行的期间,可能会有某 ...
- atitit. hb 原生sql跨数据库解决原理 获得hb 数据库类型运行期获得Dialect
atitit. hb 原生sql跨数据库解决原理 获得hb 数据库类型运行期获得Dialect #-----原理 Hibernate 运行期获得Dialect 2010-07-28 12:59 ...
随机推荐
- PIE SDK矢量分级渲染
1. 功能简介 分级渲染是矢量的一种数据表达方式.通过选取一个字段,并根据实际需要对字段的数据进行分级,并对每一级设置不同的符号,已达到区分显示的效果. 2. 功能实现说明 2.1. 实现思路及原理说 ...
- PIE SDK专题制图打开模板
1. 功能简介 在PIE SDK中,所有的制图元素.视图范围以及排版等都可以保存成一个模板,以供多次重复使用.使用时只需要打开该模板,加载相应数据,就可以直接出图了,省去了重复制作图幅的麻烦,方 ...
- curl -w函数
url_effective 最终获取的url地址,尤其是当你指定给curl的地址存在301跳转,且通过-L继续追踪的情形. http_code http状态码,如200成功,301转向,404未找到, ...
- shell 脚本学习之内部变量
一,$BASH Bash的二进制程序文件的路径 二,$BASH_ENV 这个环境变量会指向一个Bash的启动文件, 当一个脚本被调用的时候, 这个启动文件将会被读取. 三,$BASH_SUBSHELL ...
- 移动端刷新组件XtnScroll--Angular4实现
刷新组件 - 主要是学习一下Angular4所有花了我一天时间,写了这个刷新组件. 以项目开发当中,特别是手机移动端开发的时候,经常要用到就是上拉加载下一面,下拉刷新获取最新数据的功能. 在网也有很多 ...
- MVC参数自动装配
在拿到一个类型的所有属性以及字段的描述信息后,就可以通过循环的方式,根据这些数据成员的名字去QueryString,Form,Session,Cookie读取所需的数据了. 就是遍历参数,然后用反射遍 ...
- poi excel 常用api
http://www.cnblogs.com/huajiezh/p/5467821.html
- Nginx实践:(2) Nginx语法之localtion
1. 概念 location是根据uri进行不同的定位.在虚拟主机的配置中,是必不可少的.location可以将网站的不同部分,定位到不同的处理方式上. location语法格式如下: locatio ...
- HDU 2795——Billboard——————【单点更新、求最小位置】
Billboard Time Limit:8000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit St ...
- python爬虫学习(一)
#简单例子:抓取网页全部内容后,根据正则表达式,获取符合条件的字符串列表from urllib import request#正则表达式import re url = "http://www ...