前言

在日常中工作中,我们时不时会代码进行一些优化,比如用新的算法,简化计算逻辑,减少计算量等。对于java程序来说,除了开发者本身对代码优化之外,还有一个"人"也在背后默默的优化我们的代码,这个"人"就是jvm。jvm会帮我们分析出热点代码,优化代码逻辑。其中jvm最常做的优化之一就是:方法内联优化。

方法内联

什么是方法内联?又可以叫做函数内联,java中方法可等同于其它语言中的函数。关于方法内联维基百科上面解释是:

在计算机科学中,内联函数(有时称作在线函数或编译时期展开函数)是一种编程语言结构,用来建议编译器对一些特殊函数进行内联扩展(有时称作在线扩展);也就是说建议编译器将指定的函数体插入并取代每一处调用该函数的地方(上下文),从而节省了每次调用函数带来的额外时间开支。

简单通俗的讲就是把方法内部调用的其它方法的逻辑,嵌入到自身的方法中去,变成自身的一部分,之后不再调用该方法,从而节省调用函数带来的额外开支。

函数调用开销

之所以出现方法内联是因为函数调用除了执行自身逻辑的开销外,还有一些不为人知的额外开销。这部分额外的开销主要来自方法栈帧的生成、参数字段的压入、栈帧的弹出、还有指令执行地址的跳转。比如有下面这样代码:

public static void function_A(int a, int b){
//do something
function_B(a,b);
} public static void function_B(int c, int d){
//do something
} public static void main(String[] args){
function_A(1,2);
}

则代码的执行过程如下:

所以如果java中方法调用嵌套过多或者方法过多,这种额外的开销就越多。

试想一下想get/set这种方法调用:

public int getI() {
return i;
} public void setI(int i) {
this.i = i;
}

很可能自身执行逻辑的开销还比不上为了调用这个方法的额外开锁。如果类似的方法被频繁的调用,则真正相对执行效率就会很低,虽然这类方法的执行时间很短。这也是为什么jvm会在热点代码中执行方法内联的原因,这样的话就可以省去调用调用函数带来的额外开支。

这里举个内联的可能形式:

public int  add(int a, int b , int c, int d){
return add(a, b) + add(c, d);
} public int add(int a, int b){
return a + b;
}

内联之后:

public int  add(int a, int b , int c, int d){
return a + b + c + d;
}

这样除了本身的相加逻辑的开销,比内联前减少了二次调用函数带来的额外开销。

内联条件

一个方法如果满足以下条件就很可能被jvm内联。

1、热点代码。 如果一个方法的执行频率很高就表示优化的潜在价值就越大。那代码执行多少次才能确定为热点代码?这是根据编译器的编译模式来决定的。如果是客户端编译模式则次数是1500,服务端编译模式是10000。次数的大小可以通过-XX:CompileThreshold来调整。

2、方法体不能太大。jvm中被内联的方法会编译成机器码放在code cache中。如果方法体太大,则能缓存热点方法就少,反而会影响性能。

3、如果希望方法被内联,尽量用private、static、final修饰,这样jvm可以直接内联。如果是public、protected修饰方法jvm则需要进行类型判断,因为这些方法可以被子类继承和覆盖,jvm需要判断内联究竟内联是父类还是其中某个子类的方法。

所以了解jvm方法内联机制之后,会有助于我们工作中写出能让jvm更容易优化的代码,有助于提升程序的性能。

jvm之方法内联优化的更多相关文章

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

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

  2. Java 方法内联

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

  3. Java方法内联

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

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

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

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

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

  6. Java中的方法内联

    Java中的方法内联 1. 什么是方法内联 例如有下面的原始代码: static class B { int value; final int get() { return value; } } pu ...

  7. 一个关于内联优化和调用约定的Bug

    很久没有更新博客了(博客园怎么还不更新后台),前几天在写一个Linux 0.11的实验 [1] 时遇到了一个奇葩的Bug,就在这简单记录一下调试过程吧. 现象 这个实验要求在Linux 0.11中实现 ...

  8. Go 中的内联优化

    文讨论 Go 编译器是如何实现内联的以及这种优化方法如何影响你的 Go 代码. 请注意:本文重点讨论 gc,实际上是 golang.org 的 Go 编译器.讨论到的概念可以广泛用于其他 Go 编译器 ...

  9. 修改html内联样式的方法

    问题:如下图弹出页面操作不了 分析:审查元素,发现是内联元素样式z-index:19891015导致的,修改内联元素样式z-index:0发现可以操作了 解决方法:内联样式优先级高,再引入css覆盖样 ...

随机推荐

  1. python beautifulsoup基本用法-文档搜索

    以如下html段落为例进行介绍 <html> <head> <title>The Dormouse's story</title> </head& ...

  2. String字符串缓冲区、StringBuffer

    String字符串缓冲区 1.StringBuffer类 StringBuffer又称为可变字符序列,字符串缓冲区支持可变的字符串, StringBuffer是个字符串的缓冲区,即就是它是一个容器,容 ...

  3. Myeclipse-10.7.1版本破解

    自从上次写了IDEA2020版本破解方式,这次写一下Myeclipse10.7.1版本破解 下方链接是IDEA破解教程 点击即可跳转 Myeclipse下载地址这里我上传到了百度网盘    这里提取码 ...

  4. random随机数函数

  5. Python打开和关闭文件

    Python打开和关闭文件: open(文件名,打开文件的模式[,寄存区的缓冲]): 文件名:字符串值 注:文件名带有后缀名 # 打开创建好的 test.txt 文件 f = open("t ...

  6. Seaborn实现单变量分析

    import numpy as np import pandas as pd from scipy import stats,integrate import matplotlib.pyplot as ...

  7. 一款功能简约到可怜的SQL 客户端

    你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it well enough ...

  8. PHP preg_quote() 函数

    preg_last_error 函数用于转义正则表达式字符.高佣联盟 www.cgewang.com 语法 string preg_quote ( string $str [, string $del ...

  9. 从别人的代码中学习golang系列--03

    这篇博客还是整理从https://github.com/LyricTian/gin-admin 这个项目中学习的golang相关知识. 作者在项目中使用了 github.com/casbin/casb ...

  10. 【02python基础-函数,类】

    1.函数中的全局变量与局部变量全局变量:在函数和类定义之外声明的变量.作用域为定义的模块,从定义位置开始到模块结束.全局变量降低了函数的通用性和可读性,要尽量避免全局变量的使用.全局边个两一般作为常量 ...