七 晚期(运行期)优化
1 即时编译器(JIT编译器)
---当虚拟机发现某个方法或代码块的运行特别频繁时,就会把这些代码认定为“热点代码”,包括被多次调用的方法和被多次执行的循环体。
---为了提高热点代码的执行效率,在运行时,虚拟机就会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个任务的编译器称为即时编译器(JIT编译器)。
---即时编译器不是虚拟机必需的部分,虚拟机规范对其没有做任何规定,与具体的虚拟机实现有关。
2 解释器与编译器
---许多主流的商用虚拟机如HotSpot,都同时包含解释器和编译器。
---解释器和编译器两者各有优势:
· 当程序需要迅速启动和执行的时候。解释器可以首先发挥作用,省去编译的时间,立即执行;
· 在程序运行后,随着时间的推移,编译器逐渐发挥作用,把越来越多的代码编译成本地代码后,可以获取更高的执行效率;
· 当程序运行环境中内存资源限制较大,可以使用解释执行节约内存,反之,可以使用编译执行提升效率;
· 解释器还可以作为编译器激进优化时的一个“逃生门”。
---HotSpot虚拟机中内置了两个即时编译器:Client Compiler(C1编译器)、Server Compiler(C2编译器)。默认采用解释器与其中一个编译器直接配合的方式工作,程序使用哪个编译器取决于虚拟机运行的模式。
---分层编译策略:
· 第0层,程序解释执行,解释器不开启性能监控功能,可触发第1层编译;
· 第1层,也称为C1编译,将字节码编译为本地代码,进行简单、可靠的优化,如有必要将加入性能监控的逻辑;
· 第2层,也称为C2编译。将字节码编译为本地代码,会启用一些编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化。
3 编译对象和触发条件
---JIT编译方式:方法被多次调用触发的编译,编译器以整个方法作为编译对象。
---栈上替换(OSR编译):循环体被多次执行触发的编译,编译器同样以整个方法作为编译对象。
---热点探测:判断一段代码是不是热点代码,是不是需要触发即时编译。目前主要的判定方式有两种:
· 基于采样的热点探测:虚拟机会周期性地检查各个线程的栈顶,如果发现某个方法经常出现在栈顶,那这个方法就是“热点方法”。
---优点:实现简单、高效,可以很容易地获取方法调用关系。
---缺点:很难精确地确认一个方法的热度,容易因为受到线程阻塞或别的外界因素的影响而扰乱热点探测。
· 基于计数器的热点探测:虚拟机会为每个方法(甚至是代码块)建立计数器,统计方法的执行次数,如果执行次数超过一定的阈值就认为它是“热点方法”。
---优点:统计结果更加精确和严谨。
---缺点:实现比较复杂,不能直接获取到方法调用关系。
---在HotSpot虚拟机中使用的是基于计数器的热点探测,它为每个方法准备了两类计数器:方法调用计数器和回边计数器。
---方法调用计数器:统计方法被调用的次数,在Client VM下,其触发的即时编译过程如下:
---方法调用计数器热度的衰减:当超过一定的时间限度,如果方法的调用次数仍然不足以让它提交给即时编译器编译,那这个方法的调用计数器就会被减少到一半。一般是在虚拟机进行垃圾收集时顺便进行的。也可以设置为不进行热度衰减。
---回边计数器:统计一个方法中循环体代码执行的次数,在字节码中遇到控制流向后跳转的指令称为“回边”。
---回边计数器阈值计算公式:
· 虚拟机运行在Client模式下,计算公式为:方法调用计数器阈值*OSR比率/100;
· 虚拟机运行在Server模式下,计算公式为:方法调用计数器阈值*(OSR比率-解释器监控比率)/100。
---在Client VM下,回边计数器触发的即时编译过程如下:
---回边计数器没有热度衰减的过程。当计数器溢出时,它还会把方法计数器的值也调整到溢出状态,这样下次再进入该方法的时候就会执行标准编译过程(JIT编译)。
4 编译过程
---Server Compiler和Client Compiler两个编译器的编译过程是不一样的。
---Client Compiler主要的关注点在于局部性的优化,而放弃了许多耗时较长的全局优化手段,过程如下:
· 一个平台独立的前端将字·节码构造成一种高级中间代码表示(HIR),在此之前编译器会在字节码上完成一部分基础优化,如方法内联、常量传播等;
· 一个平台相关的后端从HIR中产生低级中间代码表示(LIR),在此之前编译器会在HIR上完成另外一些优化,如空值检查消除、范围检查消除等;
· 在平台相关的后端使用线性扫描算法在LIR上分配寄存器,并在LIR上做窥孔优化,然后产生机器代码。
5 编译优化技术
---编译方式执行本地代码比解释方式更快的原因:
· 虚拟机解释执行字节码时需要额外的消耗时间;
· 虚拟机对代码的优化措施几乎都集中在即时编译器中。
(1)方法内联
---主要目的是:
· 去除方法调用的成本,如建立栈帧等;
· 为其他优化建立良好的基础,方法内联膨胀之后可以便于在更大范围上采取后续的优化手段,从而获取更好的优化效果。
---Java虚拟机的内联过程:
· 编译器在进行方法内联时,如果是非虚方法,那么可以直接进行内联。
· 如果是虚方法,则会向CHA查询此方法在当前程序下是否有多个目标版本可供选择,若查询结果只有一个版本,那也可以进行内联,但是这种内联属于激进优化,需要预留一个“逃生门”,称为守护内联。如果在程序的后续执行过程中,虚拟机一直没有加载到会令这个方法的接收者的继承关系发生变化的类,那这个内联优化的代码就可以一直使用下去。但如果加载了导致继承关系发生变化的新类,那就需要抛弃已经编译的代码,退回到解释状态执行,或者重新进行编译。
· 如果CHA查询出来的结果是有多个版本的目标方法可供选择,则编译器会使用内联缓存来完成方法内联。
---注1:类型继承关系分析(CHA)技术:用于确定在目前已加载的类中,某个接口是否有多于一种的实现,某个类是否存在子类、子类是否为抽象类等信息。
---注2:内联缓存工作原理:在未发生方法调用之前,内联缓存状态为空,当第一次调用发生后,缓存记录下来方法接收者的版本信息,并且每次进行方法调用时都比较接收者版本,如果以后进来的每次调用的方法接收者版本都是一样的,那这个内联还可以一直用下去。如果发生了方法接收者版本不一致的情况,就说明程序真正使用了虚方法的多态特性,这时会取消内联,查找虚方法表进行方法分派。
(2)公共子表达式消除
---含义是:如果一个表达式E已经计算过了,并且从先前的计算到现在E中所有变量的值都没有发生变化,那么E的这次出现就成为了公共子表达式。对于这种表达式,没有必要花时间再对它进行计算,只需要直接使用前面计算过的表达式结果代替E就可以了。
---语言无关的经典优化技术之一。
(3)数组边界检查消除
---语言相关的经典优化技术之一。
---把运行期检查提到编译期完成。
(4)逃逸分析
---逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定义后,它可能被外部方法所引用,称为方法逃逸;甚至还有可能被外部线程访问到,称为线程逃逸。
---如果一个对象不会逃逸到方法或者线程之外,则可能为该变量进行如下优化:
· 栈上分配:如果一个对象不会逃逸出方法之外,那么可以让这个对象在栈上分配内存。
· 同步消除:如果一个对象不会逃逸出线程之外,那么可以将对这个对象的同步措施消除掉。
· 标量替换:如果逃逸分析证明一个对象不会被外部访问,并且这个对象可以被拆散的话,那程序真正执行的时候将可能不创建这个对象,而改为直接创建它的若干个被这个方法使用到的成员变量来代替。
---注1:标量:一个数据已经无法再分解成更小的数据来表示,如Java虚拟机中的原始数据类型(int、long等数值类型及reference类型等)。
---注2:聚合量:一个数据可以继续分解,如Java中的对象。
- 深入理解Java虚拟机 -- 读书笔记(1):JVM运行时数据区域
深入理解Java虚拟机 -- 读书笔记:JVM运行时数据区域 本文转载:http://blog.csdn.net/jubincn/article/details/8607790 本系列为<深入理 ...
- 【Todo】深入理解Java虚拟机 读书笔记
有一个在线系列地址 <深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)> http://book.2cto.com/201306/25426.html 已经下载了这本书(60多M ...
- 深入理解Java虚拟机读书笔记5----虚拟机字节码执行引擎
五 虚拟机字节码执行引擎 1 运行时栈帧结构 ---栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构,是虚拟机运行时数据区中的虚拟机栈的栈元素. ---栈帧中存储了方法的局部变 ...
- 深入理解Java虚拟机读书笔记8----Java内存模型与线程
八 Java内存模型与线程 1 Java内存模型 ---主要目标:定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节. ---此处的变量和J ...
- 深入理解Java虚拟机读书笔记6----早期(编译期)优化
六 早期(编译期)优化 1 “编译期”的含义 · 可能是指一个前端编译器把*.java文件转变成*.class文件的过程,前端编译器如:Sun的Javac.Eclipse JDT中的增量式 ...
- 深入理解Java虚拟机读书笔记4----虚拟机类加载机制
四 虚拟机类加载机制 1 类加载机制 ---概念:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型. -- ...
- 深入理解Java虚拟机读书笔记3----类文件结构
三 类文件结构 1 Java虚拟机的两种中立特性 · 平台无关性 · 语言无关性 实现平台无关性和语言无关性的基础是虚拟机和字节码存储格式(Class文件). 2 Clas ...
- 深入理解Java虚拟机读书笔记1----Java内存区域与HotSpot虚拟机对象
一 Java内存区域与HotSpot虚拟机对象 1 Java技术体系.JDK.JRE? Java技术体系包括: · Java程序设计语言: · 各种硬件平台上的 ...
- 深入理解java虚拟机读书笔记--java内存区域和管理
第二章:Java内存区域和内存溢出异常 2.2运行时数据区域 运行时数据区分为方法区,堆,虚拟机栈,本地方法栈,程序计数器 方法区和堆是线程共享的区域 虚拟机栈,本地方法栈,程序计数器是数据隔离的数据 ...
随机推荐
- 运用Turtle实现汉诺塔的可视化运行(递归算法)
运用Turtle实现汉诺塔的可视化运行(递归算法) 汉诺塔问题又名河内塔问题,是源于印度一个古老传说的益智玩具.大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆 ...
- 20164318 毛瀚逸 Exp4 恶意代码分析
---恢复内容开始--- 1 关键内容 系统运行监控 (1)使用计划任务,每隔一分钟记录自己的电脑有哪些程序在联网,连接的外部IP是哪里.运行一段时间并分析该文件,综述分析结果. (2)安装配置sys ...
- RobotFramework-RIDE环境搭建二:Robot Framework-RIDE安装过程以及踩雷点
前期准备工作: Python 2.7(上篇文章中已安装成功) Robot Framework-2.8.5 Robot Framework-RIDE-1.5.2.1 (测试用例的创建.运行可以在图形界面 ...
- 一、Flask路由介绍
Flask介绍(轻量级的框架,非常快速的就能把程序搭建起来) Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是So ...
- cf549B Looksery Party 贪心
题目大意:有n个员工,每个员工通讯录里有自己的号码和其他一些员工的号码.现在有若干员工参加一个聚会,他们会给自己通讯录里所有的人发一条短信,包括自己.现在有个人预测了每个员工会收到多少条短信,而你要寻 ...
- java web 登录后更新JSESSIONID
https://huangqiqing123.iteye.com/blog/2031455 登录前的请求一般都是http的,http是不安全的,假设用户登录前的JSESSIONID被人取得,如果登录后 ...
- git 安装部署教程
转转改改修修,能用: 查看用户名和邮箱 $ git config user.name $ git config user.email 修改用户名和邮箱 $ git config user.na ...
- 《python for data analysis》第二章,美国1880-2010年出生人口姓名的数据分析
<利用python进行数据分析>第二章的姓名例子,代码.整个例子的所有代码集成到了一个文件中,导致有些对象名如year同时作为了列名与行名,会打印warning,可分不同的part依次运行 ...
- [noip2016]洛谷2827
来一发文字证明~ 数据范围很大... 如果用priority_queue搞的话肯定是会t的. 所以肯定要想一想优化的思路. 我们发现,对于队列来讲,同加,减是不改变这个队列的大小关系的: 但是呢,切开 ...
- ss - linux网络工具
用以替代netstat 参看 http://www.cnblogs.com/peida/archive/2013/03/11/2953420.html 常用命令: ss -ptl | grep 991 ...