为什么Java程序会执行一段时间后跑的更快?

对于Java 应用,程序员之间一个认识口口相传:

要看一个Java程序跑的快不快,需要多跑几次;另外,Java程序跑一段时间之后会快起来。速度甚至能赶上 C/C++程序的速度。

如果你问为什么跑一段时间就快了呢?

一般都能听到 「因为JVM会把调用次数多的热方法编译再执行」的答案。

更通俗的话来讲, JVM 会把热方法编译成机器码,执行效率会更高。就像公司或工厂里,对于一项任务,一般老手都比新人更快,因为老手更熟悉嘛。所以招聘要求里你很少会见到指明要新人的,大部分都是要有工作经验的。

而JVM 将热方法编译生成的机器码,由于是针对当前平台,当前硬件生成的,对应用具体执行情况分析之后进行编译而成,所以就像老手一样,能更了解情况,效率当然更高。

默默在背后做编译工作的人就是 JIT (Just-In-Time) 编译器,一般也叫即时编译器。

今天我们一起来看看,这越跑越快的背后,JIT 具体是怎样工作的。

我们都知道,Java 原生就是解释型语言,也是解释执行的,怎么又有了编译执行了?

执行 java -version 的时候,我们一般能看到当前 Java 版本号之后,会有一个 mixed mode,说明当前JVM 运行在混合模式之下,即同时包含解释执行和编译执行。我们也可以通过参数强制执行只按一种模式执行。各种环境根据自己的需要选择执行的方式。

相比编译执行,解释执行要慢很多,但仍然广泛在被运用在各种虚拟机中,比如它内存占用少,应用启动时间更短。更关键的优势在于它简单。一种新语言或者一个语言的新特性出现时,在解释器中能比编译器实现要快很多。另外,开发者会考虑到性价比,一些语言特性很难,同时也不值得在实现在编译器就只使用解释器。

开发实现语言时,使用解释器只有两个要求:

1.

熟悉VM实现语言

2.

3.

理解新语言特性、语法和语义

4.

而像在JIT编译器实现新语言特性,对开发者有更多的要求:

·

熟悉目标机器的应用程序二进制接口规范

·

·

把新语言特性映射到这个目标机器的接口运行时

·

·

掌握开发编译器生成目标机器码的能力

·

而为了应用程序的执行效率、运行速度, Java 又特别需要JIT,在运行的适当时候,可以把一些高频率代码编译,换取更好的效率。

JIT就是通过将热方法、代码段编译生成机器码的形式,在下次调用到该方法时,会直接通过vtable中链接的机器码直接执行,所以效率是杠杠的。

那么问题来了,什么样的方法才算热方法,怎样来判断热方法?

对于热方法的计算,一般虚拟机内有以下几种实现方式:

o

基于方法的JIT,JVM内常用

o

o

基于踪迹的JIT, Dalvik和 TraceMonkey在使用

o

o

基于区域的JIT,HHVM 使用这种形式

o

基于方法的JIT中,一般探测热点方法有基于采样的热点探测,即周期性的去检查线程的调用栈顶,如果方法经常出现在栈顶,那它就是热点方法。另一种是基于计数器的热点探测,这种会给每个方法建立计数器,用来统计方法的执行次数。超过阈值的就认为是热点方法。

当然需要注意的是,这里统计的次数,不是绝对的次数,和我们进行限流和降级时说的类似,都是一个时间周期内的相对频率,如果在此期间没有超过,就不算,原来的次数会减少。

JIT 编译的代码,存储在 Code Cache 的内存区间。空间是有限的在JVM 启动的时候,设置了一个固定的最大值,实现形式也是个堆,在分配满时会停止编译,类卸载、替换成新版本等也会从 Code Cache中删除。

另外,在JVM JIT编译器中包含C1、C2    两种编译器,在具体的编译过程中,一般是采用分层编译,再具体使用不同的编译器,相比C1,C2编译需要更多的时间,做更多的优化等等,像内联、循环展开、逃逸分析、锁消除与合并、栈上替换……

前面我们大概了解了JIT的原理,也了解到 JIT 编译后,机器码执行效率更高,那有什么办法能了解到我们自己的应用里,JIT有没有执行,用的是C1还是C2,对哪些代码做过编译和优化呢?

我们有没有办法,能知道都有哪些方法被JIT编译了,哪些方法本来我们想要效率高一些,期待被编译却没被考虑的,能更直观的知道呢?

一个办法是应用启动时,增加 JVM 参数:

-XX:+UnlockDiagnosticVMOptions

-XX:+PrintCompilation

-XX:+PrintInlining

-XX:+PrintCodeCache

-XX:+PrintCodeCacheOnCompilation

-XX:+TraceClassLoading

-XX:+LogCompilation

-XX:LogFile=~/a.log

然后根据这些输出内容,以及日志文件里的内容,去分析。

当然,如果真的是肉眼阅读那可太累了。好在有一个优秀的开源工具用于解析日志文件。

铛铛铛,来了。

就是它, JITWatch。

https://github.com/AdoptOpenJDK/jitwatch

使用 JavaFX 开发而成,功能很强大。

你可以 通过 Open Log 直接解析上面输出的日志文件。  例如一个简单的应用,打开日志之后,会看到不同包下的内容,这里example111 是示例。

public void jitTest() {        long x = calc();        System.out.println(x);    }
    public long calc() {        long sum = 0;        for (long i=0; i< 1000000; i++) {            sum = plus(sum, i);        }        return sum;    }
    public long  plus(long a, long b) {        return a + b;    }

在点击右侧某个JIT编译过的具体方法后,点击TriView,会看到生成的节字码,以及相应的源码是如何对应到字节码和汇编代码的。

点击Chain,会看到编译链路

Inline-info 会显示哪些方法进行了内联优化。

这里看到的OSR,就是常听到的栈上替换(On-stack replacement),用于优化在解释器中执行时,向后跳转的循环分支达到某站长博客个阈值时就会被编译。

JITWatch 还有一个沙箱的环境,可以用来实验观察 JIT的行为,观察 JVM 里JIT的决策过程。

有了工具的帮助,我们能更好的理解JIT 对应用优化的决策,从而让应用性能更佳。

(0)

相关推荐

  • java虚拟机JVM执行引擎(工作过程、JIT等)

    文章目录 11. 执行引擎 11.1 执行引擎概述 11.2 执行引擎的工作过程 11.3 java代码编译和执行的过程 11.4 JIT编译器 11.5 方法调用计数器 11.6 回边计数器 11. ...

  • Java定义

    多态的定义: 多态分为编译时多态和运行时多态. 编译时多态:方法的重载 运行时多态:定义的对象引用所指向的具体类型在运行期间才能确定 运行时多态的三个条件:继承.重写.向上转型 运行时多态就是子类继承 ...

  • 后端编译与优化

    本书部分摘自<深入理解 Java 虚拟机第三版> 概述 前面讲过前端编译是将 Java 源代码编译成 Class 字节码,那么后端编译就对应把 Class 文件转换成与本地机器相关的二进制 ...

  • (9条消息) java锁升级都是在安全点吗

    前言 本文是一篇简短的杂糅. 本文源自于作者最近的一个疑问:为什么在旧版的jdk中偏向锁的移除一定要在全局安全点进行?同时在上个星期,作者参与的一个项目发生了一件怪事:一个服务莫名其妙地不接受任何请求 ...

  • 基本功 | Java即时编译器原理解析及实践

    跟其他常见的编程语言不同,Java将编译过程分成了两个部分,这就对性能带来了一定的影响.而即时(Just In Time, JIT)编译器能够提高Java程序的运行速度. 本文会先解析一下即时编译器的 ...

  • 普洱熟茶为什么要存放一段时间后,才更好喝?

      2020年进入最后的倒数,一年一度的熟茶季也即将落幕,在这近一个月的时间里,我们陆陆续续收到了众多茶友们的无念熟茶品鉴心得,大家对这款茶的甜柔顺滑给予了充分的肯定,但也有茶友反馈,汤色较浑浊,不够 ...

  • 为什么普洱熟茶,要存放一段时间后,才更好喝?

    2020年进入最后的倒数,一年一度的熟茶季也即将落幕,在这近一个月的时间里,我们陆陆续续收到了众多茶友们的无念熟茶品鉴心得,大家对这款茶的甜柔顺滑给予了充分的肯定,但也有茶友反馈,汤色较浑浊,不够透亮 ...

  • excl vba 暂停一段时间后继续执行

    waitTime = TimeSerial(Hour(Now()), Minute(Now()), Second(Now()) + 3) Application.Wait waitTime

  • 限塑令执行一段时间以后,今天喝奶茶,你随身带吸管了吗?

    自从去年限塑令出来一段时间以后,大家都在吐槽纸吸管不好用,这问题真的就在纸吸管的材料本身吗? 那是因为有人看见赚钱的商机了.话说限塑令以来,塑料吸管就取消了.然而一段时间以来,有不少网友说自己喝奶茶的 ...

  • 每天坚持跑步1小时,为什么一段时间后体重不下降了?

    想要减肥的人除了控制饮食外,一定要加强健身锻炼,运动锻炼可以促进卡路里消耗,预防脂肪的堆积,还能强化体质,塑造强健的体魄. 为了减肥而坚持健身的你,会选择什么运动呢?大部分人会选择跑步,因为跑步是一项 ...

  • 为什么跑步一段时间后,人变瘦了,面容也沧桑了?可能和这事有关

    我们都知道跑步对于身体健康是非常有益的,如果在平常的时候坚持跑步对于男性女性还是有所帮助的.而且跑步的好处众所周知,如果我们经常跑步的话,会收获非常多的好处,但是小编在这里有这样一个疑问,因为小编也是 ...

  • 每天踮脚15分钟,坚持一段时间后,你的身体可能会收获到这些好处

    因此越来越多的人开始注重养生,很多时候,养生只需要一个小动作,身体就会给你一个很好的反馈.每天踮脚15分钟,坚持一段时间,或许你会得到意想不到的好处.主要原因在于踮脚能有效的促进人体内的血液循环,促进 ...

  • 黄芪配一物,没事喝几口,一段时间后,身体也许会收获不少好评

    在民间一直流传着一句话:"外行吃人参,内行吃黄芪",可见人们对黄芪的功效给予了充分的肯定.而黄芪在补气方面也的确是独树一帜,正因如此受到了不少人的追捧,成为女性养生的首选之一. 然 ...

  • 每天起床空腹吃几粒花生,一段时间后,4个好事找上门

    不知道在日常生活中有没有喜欢吃花生的朋友呢?花生的吃法多种多样,不仅仅是生花生,还有花生酱,花生油等等,因为花生当中还有非常丰富的脂肪酸可以减少大家患上冠心病的风险,从而保护心脏,所以深受众多人士的喜 ...