Java中的方法内联

1. 什么是方法内联

例如有下面的原始代码:

static class B {
int value;
final int get() {
return value;
}
} public void foo() {
y = b.get();
// ...do stuff...
z = b.get();
sum = y + z;
}

我们首先要进行的就是方法内联,主要有下面两个目的:

  • 去除方法调用的成本,如查找方法版本、建立栈帧。
  • 为其他优化建立良好基础。

内联后代码如下:

public void foo() {
y = b.value;
// ...do stuff...
z = b.value;
sum = y + z;
}

后续,还可以进行冗余访问消除、复写传播、无用代码消除等优化操作。

2. 方法内联的重要性

方法内联是编译器最重要的优化手段,如果没有内联,多数其他优化都无法有效进行。例如下面这个例子:

public static void foo(Object obj){
if (obj != null) {
System.out.println("do something");
}
} public static void testInline(String[] args) {
Object obj = null;
foo(obj);
}

testInline()方法里其实全都是无用的代码,但是如果不做方法内联,就无法发现任何 Dead Code 的存在,因为分开看的话两个方法里面的操作可能都有意义。

3. Java中方法内联的困难

在 JVM 中,只有非虚方法,也就是使用invokespecial指令调用的私有方法、实例构造器、父类方法和使用invokestatic指令调用的静态方法才会在编译器进行解析。

而其他虚方法被invokevirtual指令调用,在调用时必须进行方法接收者的多态选择。对于一个虚方法,编译器静态地去做内联的时候很难确定应该使用哪个方法版本,这就造成了方法内联的困难。

继承类型关系分析 CHA

首先,JVM 引入了一种名为类型继承关系分析 CHA 的技术,这种技术用于在已加载的类中,确定某个接口是否有多于一种的实现、某个类是否存在子类、某个子类是否覆盖了父类的某个虚方法等信息。

编译器在进行内联时会分不同情况采取不同处理:

  • 如果是非虚方法,那么就直接进行内联。

  • 如果是虚方法,那么向 CHA 查询是否有多个目标版本可供选择。

    • 如果只有一个版本,就直接内联,称为守护内联。但由于 Java 程序动态连接,不知道什么时候就会加载到新的类型而改变 CHA 的结论,所以要留好逃生门,假如程序后续执行中加载了导致继承关系发生变化的新类,那么必须抛弃已经编译的代码,退回到解释状态进行执行,或者重新编译。

    • 如果有多个版本可供选择,那即时编译器使用内联缓存来缩减方法调用的开销。内联缓存是一个建立在目标方法正常入口之前的缓存。在未发生方法调用时,内联缓存为空。第一次调用发生后,缓存记录下方法接收者的版本信息,并且在每次进行调用前都检查版本。

      • 如果每次调用的方法接收者版本是一样的,那称为单态内联缓存,通过缓存来调用,相比不内联只多了一次类型判断的开销。
      • 如果出现方法接收者不一致的情况,就退化为超多态内联缓存,开销相当于真正查找虚方法表来进行方法分派。
      • 当缓存未命中的时候,大多数JVM的实现时退化成超多态内联缓存,也有一些JVM选择重写单态内联缓存,就是更新缓存为新的版本。这样做的好处是以后还可能会命中,坏处是可能白白浪费一个写的开销。

Java中的方法内联的更多相关文章

  1. Java 方法内联

    什么是Java 方法内联? 我们先来看看普遍的内联函数含义.在维基百科中解释为: 内联函数:在计算机科学中,内联函数(有时称作在线函数或编译时期展开函数)是一种编程语言结构,用来建议编译器对一些特殊函 ...

  2. jvm之方法内联优化

    前言 在日常中工作中,我们时不时会代码进行一些优化,比如用新的算法,简化计算逻辑,减少计算量等.对于java程序来说,除了开发者本身对代码优化之外,还有一个"人"也在背后默默的优化 ...

  3. JVM 学习(二)Java 内存模型、方法内联、逃逸 --- 2019年4月

    1.Java 的内存模型 定义了 happens-before,如果同一个线程中,字节码的先后顺序,后者观测了前者的运行结果,那么就会按顺序执行. Java 线程之间的通信由 Java 内存模型控制. ...

  4. 深入理解java虚拟机(十四)正确利用 JVM 的方法内联

    在IntelliJ IDEA里面Ctrl+Alt+M用来拆分方法.选中一段代码,敲下这个组合,非常简单.Eclipse也用类似的快捷键,使用 Alt+Shift+M.我讨厌长的方法,提起这个下面这个方 ...

  5. Java方法内联

    一.概念 方法内联就是把调用方函数代码"复制"到调用方函数中,减少因函数调用开销的技术   函数调用过程 1.首先会有个执行栈,存储它们的局部变量.方法名.动态连接 2.当一个方法 ...

  6. Access中多表内联的SQL写法

    在Access中多表内联,可以使用传统的where条件逐行筛选,如: SELECT SNAME,CNAME,DEGREE FROM STUDENT,COURSE,SCORE where student ...

  7. C#效率优化(2)-- 方法内联

    一.JIT编译器可以通过将方法内联展开(Method Inline Expansion)来提升效率,类似C++中的内联函数(Inline Function),与C++的内联函数不同的是,C#并不支持内 ...

  8. ARM嵌入式开发中的GCC内联汇编__asm__

    在针对ARM体系结构的编程中,一般很难直接使用C语言产生操作协处理器的相关代码,因此使用汇编语言来实现就成为了唯一的选择.但如果完全通过汇编代码实现,又会过于复杂.难以调试.因此,C语言内嵌汇编的方式 ...

  9. [03]java中的方法以及控制语句

    00 Java中的语句块 语句块(有时叫做复合语句),是用花括号扩起的任意数量的简单Java语句.块确定了局部变量的作用域.块中的程序代码,作为一个整体,是要被一起执行的.块可以被嵌套在另一个块中,但 ...

随机推荐

  1. 【LeetCode】1020. Partition Array Into Three Parts With Equal Sum 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  2. 【LeetCode】901. Online Stock Span 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 单调递减栈 日期 题目地址:https://leet ...

  3. 【LeetCode】429. N-ary Tree Level Order Traversal 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 方法一:BFS 方法二:DFS 参考资料 日期 题目 ...

  4. netty系列之:从零到壹,搭建一个SOCKS代理服务器

    目录 简介 使用SSH搭建SOCKS服务器 使用netty搭建SOCKS服务器 encoder和decoder 建立连接 ConnectHandler 总结 简介 上一篇文章,我们讲到了netty对S ...

  5. 【计组】《计算机组成与体系结构性能设计》William Stallings 第2部分 计算机系统 第3章 计算机功能和互连的顶层视图

    关键词 address bus 地址总线 asynchronous timing 异步时序 bus 总线 bus arbitration 总线仲裁 bus width 总线宽度 centralized ...

  6. 第五十一个知识点:什么是基于ID的加密的安全模型,然后描述一个IBE方案

    第五十一个知识点:什么是基于ID的加密的安全模型,然后描述一个IBE方案 在公钥密码学中,如果Alice想要给Bob发送一条消息,她需要Bob的公钥,一般来说公钥都很长,就像一个随机的字符串. 假设A ...

  7. matplotlib 高阶之Transformations Tutorial

    目录 Data coordinates Axes coordinates Blended transformations 混合坐标系统 plotting in physical units 使用off ...

  8. docker学习:docker---centos安装

    查看目标镜像 docker search centos 拉取镜像 docker pull centos 查看镜像 docker images 启动镜像 docker run -itd --privil ...

  9. Centos下查看cpu核数

    1.概念物理CPU:实际Server中插槽上的CPU个数.物理cpu数量:可以数不重复的 physical id 有几个. 2.逻辑CPULinux用户对 /proc/cpuinfo 这个文件肯定不陌 ...

  10. 初识python:tkinter 实现 弹球小游戏(非面相对象)

    通过 tkinter 采用非面相对象式实现弹球小游戏(使用蹩脚式面相对象实现). #!/user/bin env python # author:Simple-Sir # time:2020/8/3 ...