我是靠谱客的博主 彩色石头,最近开发中收集的这篇文章主要介绍编译器优化 [1]字节码是如何运行的?  查看使用哪种运行方式,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

字节码是如何运行的?

 

Java有两种运行方式:

  • 解释执行:由解释器一行一行翻译执行
  • 编译执行:把字节码编译成机器码,直接执行机器码

两种运行方式对比:

  •   解释执行
    • 优势在于没有编译的等待时间
    • 性能相对差一些
  • 编译执行:
    • 运行效率会高很多,一般认为比解释执行快一个数量级
    •  带来了额外的开销(Cpu开销,内存开销)

  查看使用哪种运行方式

java -version
> java version "1.8.0_251"
> Java(TM) SE Runtime Environment (build 1.8.0_251-b08)
> Java HotSpot(TM) 64-Bit Server VM (build 25.251-b08, mixed mode)

  mixed mode : 混合模式, 部分代码解释执行,部分代码编译执行  

  java -Xint -version   设置JVM的执行模式为解释执行模式     interpreted mode

 java -Xcomp -version   设置JVM优先以编译模式运行,不能编译的,以解释执行运行     

 java -Xmixed -version   设置JVM混合模式运行

一般情况下一开始一般由解释器解释执行

当虚拟机发现某个方法或代码块的运行特别频繁的时候,就会认为这些代码是 〃热点代码〃。

为了提高热点代码的执行效率,会用即时编译器(也就是JIT ) 把这些热点代码编译成与本地平台相关的机器码,并进行各层次的优化。

HotSpot 中有两个即时编译器,分别是C1、C2编译器

 C1 编译器 

  • 是一个简单快速的编译器,主要关注局部性的优化
  • 适用于执行时间较短或对启动性能有要求的程序。例如,GUI应用对界面启动速度就有一定的要求
  • 也被称为是 Client Compiler

 C2 编译器 :

  • 是为长期运行的服务器端应用程序做性能调优的编译器
  • 适用于执行时间较长或对峰值性能有要求的程序
  • 也被称为是 Server Compiler

各层次的有优化   

Jdk7 后引进了分成编译。Jdk8默认开启分层编译

        0:解释执行

        1:简单的C1编译,会用C1编译器进行一些简单的优化,不开启Profiling (就是jvm监控)

        2:受限的C1编译,仅执行带方法调用次数以及循环回边执行次数 Profiling 的C1编译

        3: 完全C1编译,会执行带有所有Profiling的C1代码

        4: 第4级别,也就是最高级别。 C2编译,使用C2编译进行优化,该级别会启用一些编译耗时较长的优化,一些情况下会根据性能监控信息进行一些非常激进的性能优化

级别越高,应用启动越慢,优化的开销越高,峰值性能也越高

Jvm如何找到热点代码的判断思路

  •         基于采样的热点探测 (周期检查线程的栈底。  执行方法会创建对应方法的栈帧,压入到虚拟机栈中,如果一个方法老是出现在栈底,就说明被调用次数很多,是个热点方法)
  •         基于计数器的热点探测 (Hotspot使用这个)(为每个方法或代码块建立计数器,统计执行次数,超过一定阈值,就认为是热点方法)      

Hotspot 有两类计数器

  • 方法调用计数器 Invocation Counter 
    • 用于统计方法被调用的次数,在不开启分层编译的情况下,在C1编译器下的默认阈值是1500次,在C2模式下是10000次,也可用 -XX:CompileThreshold=N 指定阈值
  • 回边计数器 Back Edge Count
    • 用于统计一个方法中循环体代码执行的次数,在字节码中遇到控制流向向后跳转的指令称为 “回边” (Back Edge)。在不开启分层编译的情况下,C1编译器下的默认阈值是13995,C2默认是10700,可以使用 -XX:OnStackReplacePercentage=N 指定阈值。
    • 建立回边计数器的主要目的是为了触发 OSR (OnStackReplacment)编译。
  • 当开启分层编译时,JVM会根据当前待编译的方法数以及编译线程数来动态调整阈值, -XX:CompileThreshold=N    -XX:OnStackReplacePercentage=N   都是失效。

方法调用计数器执行流程

如果不做任何设置,方法调用计数器统计的并不是方法被调用的绝对次数,而是一个相对的执行频率, 即一段时间之内方法被调用的次数。当超过一定的时间限度,如果方法的调用次数仍然不足以让它提 交给即时编译器编译,那这个方法的调用计数器就会被减少一半,这个过程称为方法调用计数器热度 的衰减,而这段时间就称为此方法统计的半衰周期。进行热度衰减的动作是在虚拟机进行垃圾收集时 顺便进行的,可以使用虚拟机参数-XX: -UseCounterDecay来关闭热度衰减,让方法计数器统计方法 调用的绝对次数,这样,只要系统运行时间足够长,绝大部分方法都会被编译成本地代码。另外,可 以使用-XXtounterHalfLifeTime参数设置半衰周期的时间,单位是秒。

回边计数器执行流程


最后

以上就是彩色石头为你收集整理的编译器优化 [1]字节码是如何运行的?  查看使用哪种运行方式的全部内容,希望文章能够帮你解决编译器优化 [1]字节码是如何运行的?  查看使用哪种运行方式所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部