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】914. X of a Kind in a Deck of Cards 解题报告(Python & C++)

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

  2. idea使用教程-安装

    [1]将安装包进行解压-->选择固态盘符 [2]发送到桌面快捷方式,生成一个快捷方式 [3]打开: 选择主题: 先进入再说,免费试用: 创建一个项目: 选择JDK: 找到jetbrains-ag ...

  3. Iptables 实操

    目录 Iptables之实操 简介 名称概念: 四表中常用的表 Nat表 Filter表 iptables表和链的工作流程图 iptables过滤图 Iptables安装 Iptables 命令说明 ...

  4. 使用Xcode 制作自定义storyboard启动界面,供uniAPP使用。

    1新建项目 想要全屏显示并适应所有尺寸的iPad和iphone 需要用750*1624 2X 和 1125 * 2436 3X大小的图片 这里做完就可以导出文件了 把文件和图片放到一起 见下图 命名规 ...

  5. vue 滚动公告

    <!-- 滚动公告 --> <div class="textArr"> <p class="slice-enter-active" ...

  6. [Git]解决Permission denied, please try again问题

    在gitlab上传项目的时候出现Permission denied, please try again问题, 网上有很多解释,但是都没能解决我的问题,后来经过自己尝试成功了,这里把经验分享给大家. 在 ...

  7. X86系统或intel RK主板上EDP转LVDS屏转接板|CS5211DP转LVDS设计

    众所周知LVDS接口是美国NS美国国家半导体公司为克服以TTL电平方式传输宽带高码率数据时功耗大,电磁干扰大等缺点而研制的一种数字视频信号传输方式.由于其采用低压和低电流驱动方式,实现了低噪声和低功耗 ...

  8. Java 字符与字符串

    字符 // 定义字符 char c1 = 'a'; char c2 = '1'; char c3 = '中'; // 自动装箱 Character c = c1; // 自动拆箱 c1 = c; // ...

  9. python使用String的Template进行参数动态替换

    1.前言: 之前使用string的find(),从指定的param里面查找,是否包含了某个字符,有的话,使用replace进行替换,一个接口的param要替换的参数少的话,使用这种方式,的确可行,如果 ...

  10. [ bootstrap ] 实现卡片里面包含图片、内容、操作按钮,形成左中右的布局

    描述: 如图 实现: <div class="card border-0 mb-3 mt-3"> <!-- 列表头部 --> <div class=& ...