前言

视频教程:https://www.bilibili.com/video/BV1Dz4y1A7FB?p=2&vd_source=85ac5ee1b07df12a44b648a8751d30f6

相关知识点

执行引擎的功能

将字节码指令解释/编译为对应平台上的本地机器指令

执行引擎的工作原理

所有的Java虚拟机的执行引擎输入、输出都是一致的:输入的是字节码二进制流,处理过程是字节码解析执行的等效过程,输出的是执行结果。

image-20240421174951328

代码编译和执行的过程

  • javac.exe的执行。由Java源码编译器来完成。

image-20240421175039930

  • java.exe的执行。由JVM执行引擎来完成。

image-20240421175123690

JAVA编译器

  • 前端编译器:把.java文件转变成.class文件的过程
  • 后端编译器(JIT):把字节码转变成机器码的过程。
  • 静态提前编译器(AOT):

JAVA解释器

当Java虚拟机启动时会根据预定义的规范对字节码采用逐行解释的方式执行,将每条字节码文件中的内容“翻译”为对应平台的本地机器指令执行。

为了满足Java程序实现跨平台特性,因此避免采用静态编译的方式直接生成本地机器指令,从而实现解释器在运行时采用逐行解释字节码执行程序。

  • 字节码解释器。纯软件代码模拟字节码的执行,效率非常低下
  • 模板解释器。每一条字节码和一个模板函数相关联

为什么说JAVA是半编译半解释型语言

image-20240421175903983

详细原因可以参考JavaGuide的面试宝典

JIT

虚拟机将源代码直接编译成和本地机器平台相关的机器语言。

为什么有了JIT还要保留解释器

当程序启动后,解释器可以马上发挥作用,省去编译的时间,立即执行。
编译器要想发挥作用,把代码编译成本地代码,需要一定的执行时间。但编译为本地代码后,执行效率高。

热点代码及探测方式

是否需要启动JIT编译器将字节码直接编译为对应平台的本地机器指令,则需要根据代码被调用执行的频率而定。

  • 方法调用计数器
  • 回边计数器

JVM启动方式

  • Xint:完全采用解释器模式执行程序;
  • Xcomp:完全采用即时编译器模式执行程序。如果即时编译出现问题,解释器会介入执行。
  • Xmixed:采用解释器+即时编译器的混合模式共同执行程序。

C1和C2编译器

在HotSpot VM中内嵌有两个JIT编译器,分别为Client Compiler和Server Compiler,但大多数情况下我们简称为C1编译器和C2编译器(默认使用)。

  • -client:指定Java虚拟机运行在Client模式下,并使用C1编译器;
    • C1编译器会对字节码进行简单和可靠的优化,耗时短。以达到更快的编译速度。
    • client启动快,占用内存小,执行效率没有server快,默认情况下不进行动态编译,适用于桌面应用程序。
  • -server:指定Java虚拟机运行在Server模式下,并使用C2编译器。
    • C2进行耗时较长的优化,以及激进优化。但优化的代码执行效率更高。
    • server启动慢,占用内存多,执行效率高,适用于服务器端应用;

C1和C2编译器的优化策略

  • C1编译器
    • 方法内联:将引用的函数代码编译到引用点处,这样可以减少栈帧的生成,减少参数传递以及跳转过程
    • 去虚拟化:对唯一的实现类进行内联
    • 冗余消除:在运行期间把一些不会执行的代码折叠掉
  • C2编译器
    • 标量替换:用标量值代替聚合对象的属性值
    • 栈上分配:对于未逃逸的对象分配对象在栈而不是堆
    • 同步消除:清除同步操作,通常指synchronized

一般来讲,JIT编译出来的机器码性能比解释器高。
C2编译器启动时长比C1编译器慢,系统稳定执行以后,C2编译器执行速度远远快于C1编译器。

面试题

你是怎么指定JVM启动模式?(字节跳动)

1
JVM启动方式

那你知道-server和-client的区别吗?(美图)

1
C1C2编译器