深入理解jvm - 编译优化(下)

简介: 深入理解jvm - 编译优化(下)



概述

  1. 补充后端优化的另一项内容提前编译器的处理
  2. 介绍jvm的几项重点优化措施
  1. 方法内联(重要)
  2. 逃逸分析(先进)
  3. 公共子表达式消除(经典)
  4. 数组边界检查消除(语言经典)

后端优化

提前编译器

提前编译器的历史其实已经很久了,但是在java领域知道andirod的崛起才被java关注,在讲解关于提前编译器的关注之前,我们来看下提前编译器的优劣

优点

  • 解决即时编译器在程序中占用运算资源。
  • 即时编译器进行缓存加速
  • 提前编译的代码质量。

书中提到了过程间分析指的是什么?

目前的java在过程间分析优化力度不够,同时由于静态编译的方式可以在全程序进行优化。

java的实践

针对上面的优点,jdk9实现了一个Jactc 提前编译器。说完提前编译器的优势,下面看下即时编译器的优势:

  1. 性能分析指导优化:对于一些动态代码和抽象方法,可以通过动态分析得到
  2. 激进型的优化:可以做一些并不保证完全正确的深度优化,并且可以回退到保护程序。
  3. 链接时优化:java天生支持即时编译产生本地代码。

关于提前编译的内容只需要基本了解即可。下面我们来看下关于jvm更多的底层优化。

底层优化

下面是关于jvm的底层优化内容,jvm的底层优化内容非常多,比如:方法内联、冗余重复消除、复写传播、无用代码消除等等。这里挑选了书中的几项内容进行介绍:

  • 方法内联(重要)
  • 逃逸分析(先进)
  • 公共子表达式消除(经典)
  • 数组边界检查消除(语言经典)

方法内联

含义:即把被内联的方法搬到内联块的内部。简单来说就是把多层方法嵌套调用合并到一个方法,减少栈桢堆积。

如何实现?

实现的前提条件:首先必须是 非虚方法,即可以不通过虚方法调用的静态方法。

C和C++使用明确虚和非虚方法规划界限。

Java的具体实现:引入类型继承关系分析和实现,确定在目前已加载的类中,某个接口是否有多于一种的实现、某个类是否存在子类、某个子类是否覆盖了父类的某个虚方法等信息”。

上方简单来说可以概括为下面这几点:

  1. 确定接口的实现者以及是否可以实现
  2. 是否有继承关系
  3. 是否存在重写方法

方法逃逸

逃逸分析的基本原理是:分析对象动态作用域,当一个对象在方法里面被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他方法中。

一个对象在方法定义中有可能被外部引用,这又引申出一个重要的优化手段:栈上分配,栈上分配简单来说就是可以减少堆空间的开辟并且提高内存的回收效率。

java只支持方法的逃逸,并不支持线程的逃逸。

书中介绍目前逃逸分析的情况如下:

  1. 改进空间非常大
  2. jdk6才初步支持
  3. 涉及复杂的算法

另一项优化方式是标量替换:

什么是标量:如果变量无法更少的单位表示(int, byte, boolean等),那么这些变量成为标量。

什么是聚合量:可以继续分解的叫做聚合量。

标量替换:把一个java对象拆散,根据程序的访问情况将其用于成员变量恢复和访问。

结合逃逸分析和标量替换,**逃逸分析会把不能被外部访问并且可以被标量替换表示的对象进行不创建对象。**同样再次强调只支持方法内处理,不支持方法逃逸。

然后是同步消除的优化:

同步消除:线程同步本身是一个相对耗时的过程,如果逃逸分析能够确定一个变量不会逃逸出线程,无法被其他线程访问,那么这个变量的读写肯定就不会有竞争,对这个变量实施的同步措施也就可以安全地消除掉。

最后如果一个变量不会出现逃逸,那么动解除同步措施。

公共子表达式

什么是公共子表达式?如果一个表达式E之前已经被计算过了,并且从先前的计算到现在E中所有变量的值都没有发生变化,那么E的这次出现就称为公共子表达式。对于这种表达式,没有必要花时间再对它重新进行计算,只需要直接用前面计算过的表达式结果代替E。

案例:

int d = (c * b) * 12 + a + (a + b * c);

如果此时表达式被计算过一遍,他会被替换为下面的方式:

int d = E * 12 + a + (a + E);

数组边界检查消除

java的数组和c以及c++的数组不同他并不是裸指针的方式操作数组,为了保证数组的访问安全,jvm的底层在每次的操作的时候都需要对于数组的边界进行检查操作,即一个含头不含尾的判断:[start, end).

针对这个问题,java是通过如下的方式考虑优化的:

  1. 如果可以界定数组访问范围,理论上可以抵消数组访问的消耗
  2. 提前到编译期间完成
  3. 隐式异常处理:比如空指针和除数为0的异常。

最终处理方式:

使用一个segment fault 信号进行替注册,保证多数访问不为null时候不进行判断为空的操作。一旦异常则转到异常处理器处理并且抛出异常。

但是这种处理方式有问题:**用户态和内核态的频繁转换。**但是hotspot会根据实际的方式进行动态判断选择使用边界检查消除还是使用原始的策略模式运行。

总结

本节内容较为简单,主要讲述了jvm的优化方式,包括后续的底层优化方式,关于底层优化的内容实际上非常多,但是本文只记录了书中提到的四种重要的优化方式。

写在最后

关于jvm的基本内容已经介绍完毕,下一节为总结内容。

相关文章
|
2月前
|
前端开发 Java 编译器
深入理解jvm - 编译优化(上)
深入理解jvm - 编译优化(上)
83 0
|
3月前
|
缓存 监控 算法
jvm性能调优实战 - 39一次大促导致的内存泄漏和Full GC优化
jvm性能调优实战 - 39一次大促导致的内存泄漏和Full GC优化
72 0
|
4月前
|
存储 监控 安全
Java虚拟机的锁优化策略
Java虚拟机的锁优化策略
28 0
|
3月前
|
架构师 Java
jvm性能调优实战 - 35电商APP后台系统如何对Full GC进行深度优化
jvm性能调优实战 - 35电商APP后台系统如何对Full GC进行深度优化
52 0
|
7月前
|
分布式计算 Java 开发者
GitHub爆款!Java性能优化:轻松道破软件性能调优,不止搞定JVM
今天给大家带来的是:周明耀老师的 《大话Java性能优化:轻松道破软件性能调优方法论和具体实现路径》,全面细致,一本书搞定性能优化 周明耀是谁? 12年投资银行项目、分布式计算项目工作经验,IBM开发者论坛专家作者。一名IT技术狂热爱好者,一名顽强到底的工程师。推崇技术创新、思维创新,对于新技术非常的热爱,致力于技术研发、研究,通过发布文章、书籍、互动活动的形式积极推广软件技术。欢迎添加作者“michael_tec”,共同探讨IT技术话题。
|
3月前
|
监控 数据可视化 Java
jvm性能调优实战 - 31从测试到上线_如何分析JVM运行状况及合理优化
jvm性能调优实战 - 31从测试到上线_如何分析JVM运行状况及合理优化
53 1
|
7月前
|
开发框架 前端开发 Java
JVM学习笔记(二)------Java代码编译和执行的整个过程
JVM学习笔记(二)------Java代码编译和执行的整个过程
|
5月前
|
Arthas 监控 算法
JVM调优篇:探索Java性能优化的必备种子面试题
本文将带你深入了解JVM调优的重要性、常见问题以及一些实用的调优工具和方法,助你在面试的过程中轻松应对
132 0
JVM调优篇:探索Java性能优化的必备种子面试题
|
3月前
|
存储 缓存 算法
jvm性能调优实战 - 34十万QPS的社交APP 如何优化GC性能提升3倍?
jvm性能调优实战 - 34十万QPS的社交APP 如何优化GC性能提升3倍?
64 0
jvm性能调优实战 - 34十万QPS的社交APP 如何优化GC性能提升3倍?
|
3月前
|
Java
jvm性能调优 - 17案例实战_每日上亿请求量的电商系统 老轻代垃圾回收参数如何优化
jvm性能调优 - 17案例实战_每日上亿请求量的电商系统 老轻代垃圾回收参数如何优化
79 0