JVM JIT

JIT Just In Time,JVM中的一种即时编译技术,目的是为了提升程序的运行效率。

先说一下前提,Java 是一种解释型语言,我们写完Java 代码后,编译器会把Java 编译为对应的字节码,然后由JVM解释执行。但是解释执行,每次执行时都需要对应的去逐条翻译、逐条执行,执行效率比较低下。

后来为了处理 慢 这个问题,JVM 引进了JIT。

JVM的对于JIT使用的运作流程是这样的:

首先我们的Java代码由javac 等编译器 编译为JVM可执行的字节码(ByteCode),然后JVM 会判断这段代码是否为热点代码,如果是那么使用JIT技术,如果不是那么解释执行,最后变成机器码,由操作系统分配然后CPU具体执行。

这里有具体的JVM参数能够调节下述流程:

-Xint全部使用字节码解释执行,这个是最慢的,慢的惊人,通常要比其他方式慢一个数量级左右。

-Xcomp相反,全部被编译成机器码执行,速度是很快的,但是存在一个缺陷,-Xcomp的策略过于简单。

-Xmixed,是一种自适应的方式,有的地方解释执行,有的地方编译执行,具体的策略要依据profile的统计分析来判断。

那具体的JIT操作,就是并非由我们的JVM去解释执行字节码,而是将得到的字节码直接编译成可执行的机器码,之后再调用、执行这一块的代码的时候直接使用机器码就ok了,省去了额外的编译或者解释。

具体的哪一类去解释,这是有具体的热点代码的判断策略来决定的。最常见的类型 比如循环体,高频执行,还有比如一些热点函数。

那既然这样快,为什么不全都去编译执行呢,因为我们程序中有挺大一部分调用频次比较低,并且一次编译的花销要比解释执行大不少,还会有额外的操作。这时去使用JIT就得不偿失了。

除了上述主要的特点外,JVM还有一个很棒的特性叫做自优化,当JIT对一块代码结构非常了解后,会做出具体的优化策略(比如何时从寄存器取值、何时从主存取值)

具体对于我们应该怎么使用或者说利用呢,下面马上介绍

如何选择:

JIT在运行时分为两种模式,客户端&服务端模式(-client、-server),这两种区别还是很大的。-client时会采用一个叫做C1的轻量级编译器,-server时会采用一个叫做C2的重量级编译器。-server 相对于 -client来说编译更彻底,性能也更好。在我们查看电脑的Java会有一个-server或者-client的标示。

这一块需要我们去调配JVM,选择适合我们的编译模式。具体的指定方式:-cient,-server 或是-xx:+TieredCompilation,长时运行就选择server多层编译方式,如果仅仅是临时执行或者短暂执行去选择-client。

如何调优过程:

优化代码缓存相关。

当JVM编译代码时会将汇编指令集保存在代码缓存中,并且这个缓存大小是固定的,当刚开始的时候把这块缓存填满后JVM后续除已缓存的代码外,只能通过解释来执行了。

这其实就是选择-server或者-client 的主要依据了,因为-server方式对热点代码要求会比较高,而-client相对来说就比较简单了对应的会产生大量的热点代码。

除此之外,默认的缓存大小总是少得可怜,我们在运行一些大的、长时项目是时需要适当的调大这一块区域。

-XX:InitialCodeCacheSize=N 修改默认缓存大小

–XX:ReservedCodeCacheSize=N 修改最大缓存大小。

编译阀值相关。

在JVM中存在这么两类计数器,一种是函数的调用次数,另一种是方法中循环被回弹的次数。(这里敲下黑板,回弹低点可不仅仅只有循环体结束处,还有可能是continue)

这两个技术相关的,就是用来判断是否达到标准去编译它。如果有,排队编译。

如果一个函数调用过程中,或者一个循环体执行过程中,虽然马上还要调用或者还会继续下一次循环,这时候也是会触发一个编译操作。将编译的结果替换当前执行的部分,这个操作叫做栈上替换。

具体使用:

-XX:CompileThreshold=Nflag 指定需要的编译次数,-client 默认应该是1500,-server为10000。这东西的修改需要一点点试调。

如果想监控或者观察JVM的编译过程,可以指定-XX:+PrintCompilation,来打印JVM中的编译过程,这一块的信息通过jstat就能看到

jstat -compiler 进称id

编译过程很直观,显然是异步的,具体的数量通过-XX:CICompilerCount=N 调整。

具体的场景,需要具体的调节,没有最好的,只有最合适的。

其实 除了官方的HotSpot JVM,IBM的J9 JVM也是非常值得看一看,对了还有一个叫做classic JVM。

比较着去学习,感觉效果更明显~

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JVM《 零  JVM 相关简介&内存模型》

    提起Java,我们首先想到的是Java 语言。其实Java 是包括Java 语言、Java虚拟机规范两部分的。Java 不赘述,要说的是JVM, 即 Java ...

    邹志全
  • shell -- 进程管理系列命令浅析

    linux 常用的命令工具非常多,除了cd、ls、mkdir、cp、mv这些非常常用和简单的命令,这里对于开发和排查问题过程中进程相关常用的几个命令进行介绍

    邹志全
  • JVM 监控 1

    服务监控是一个服务中非常重要的组成部分,直接决定了问题的发现及排查速度,并且从一定程度上提高服务一个周期内的可用性。在Java服务中,除了对于 业务、接口耗时&...

    邹志全
  • pycharm配置与使用技巧备忘-2019

    pycharm也许是最好的python开发ide,自己几乎每一台电脑都有安装,这里备忘一下自己的配置和使用技巧,方便自己还有他人。

    皮皮熊
  • spss C# 二次开发 学习笔记(六)——Spss统计结果的输出

    Spss的二次开发可以很简单,实例化一个对象,然后启用服务,接着提交命令,最后停止服务。 其中重点为提交命令,针对各种统计功能需求,以及被统计分析的数据内容等,...

    用户1637609
  • 激光SLAM概述

    动态物体 环境变化 几何结构相似环境 建图的操作复杂 全局定位 地面材质的变化 地面凹凸不平 机器人载重的改变

    小飞侠xp
  • Redis的数据类型以及各类型的操作

     点击中⽂官⽹查看命令⽂档http://redis.cn/commands.html

    skylark
  • 多态和封装

    术语多态(polymorphism)源自希腊语,意思是“有多种形态”。这大致意味着即便你不知道变量指向的哪种对象, 也能够对其执行操作,且操作的行为将随所属的...

    py3study
  • 使用双buffer无锁化

    所谓双buffer技术,其实就是准备两个Obj,一个用来读,一个用来写。写完成之后,原子交换两个Obj;之后的读操作,都放在交换后的读对象上,而原来的读对象,在...

    awk
  • Entity Framework Core 2.1,添加种子数据

    EFCore 2.1出来有一段时间了,里面的新功能还没怎么用,今天研究下如何使用EF Core 2.1添加种子数据。

    solenovex

扫码关注云+社区

领取腾讯云代金券