news 2026/9/3 0:45:22

深入JVM(三):JVM执行引擎

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深入JVM(三):JVM执行引擎

JVM执行引擎

一、JVM前后端编译

  • 前端编译:使用编译器将Java文件编译成class字节码文件
  • 后端编译:将class字节码文件编译成机器码指令

java 跨平台直接理解:前端编译将java文件编译成class文件,
然后使用jvm(后端编译(所以跨平台需要在多个平台上设计jvm将class文件编译成对应平台上的机器码指令))将class文件编译成机器码指令

二、解释执行 & 编译执行

2.1 解释执行

JVM中的**解释器(Interpreter)**读取字节码文件,逐行翻译成机器码(Native Code)并立即执行。翻译一句,执行一句。

  • 优点:
    启动快: 不需要等待编译过程,程序一启动就可以立即运行。
    内存占用少: 不需要存储编译后的机器码。

  • 缺点:
    运行慢: 每次执行都需要重复“翻译”的过程(比如一个循环跑100万次,就要翻译100万次),效率低下。

3.1 编译执行

JVM通过热点探测(HotSpot Detection) 监控程序运行。当发现某段代码(如某个方法或循环)执行频率很高(被称为“热点代码”)时,JIT会把这段字节码一次性编译成本地机器码,并缓存起来。下次再执行这段代码时,直接运行机器码,无需翻译。

  • 优点:
    运行极快: 执行的是优化后的本地机器码,速度接近C/C++。
    深度优化: JIT在编译时会进行各种优化(如方法内联、死代码消除、逃逸分析等)。

  • 缺点:
    启动延迟: 编译过程需要消耗时间(编译耗时),可能导致程序刚启动时负载较高。
    占用内存: 需要专门的内存(Code Cache)来存储编译后的机器码。

既然编译执行的速度比解释执行快,那么JVM为什么还是用解释执行呢?
虽然编译执⾏可以将越来越多的代码编译成本地代码,这样可以减少解释器的中间损耗,获得更⾼的执⾏效率。但是,这也意味着对内存有更多的资源限制,在很多资源⽐较紧张的场景,⽐如客户端应⽤,嵌⼊式系统等,使⽤解释执⾏就能更节约内存。

编译执行后的代码存储的位置是Code Cache,处于本地内存中(类似元空间)

三、识别热点代码

  1. 方法调用计数器: 记录方法的调用次数,如果超过阈值,则将方法存入code cache中,JVM的默认阈值为10000,可以使用-XX: CompileThreshold=N 来设置阈值

  2. 回边计数器:统计一个方法中循环体代码执行的次数。在class字节码文件中有例如goto等标志识别。服务端模式默认阈值为10700。

客户端编译器(C1)和服务端编译器(C2)

  • C1:相当于一个初级翻译。编译过程中,C1会对字节码进行简单和可靠的优化,耗时短,以达到更快的编译速度。启动快,占用内存小。但是翻译出来的机器码优化程度不高。适合小巧的桌面应用,所以称为客户端编译器

  • C2:相当于是⼀个⾼级翻译。编译过程中,C2会对字节码进⾏更激进的优化,优化后的佮代码执⾏效率更⾼。但是相应的,⼯作量也变得更⼤了。C2的启动更慢,占⽤内存也更多。进⾏耗时较⻓的优化,以及激进优化,但优化的代码执⾏效率更⾼。启动慢,占⽤内存多,执⾏效率⾼。⽐较适合于⼀些资源充裕的服务级应⽤,因此也称为服务端编译器。

解释执行不会交给C1、C2进行分析,所以不会进行优化

四、后端热点代码优化

如果JVM识别到一段代码是热点代码,就会使用JIT编译器进行提前编译迁移,那么在这个过程中,会对编译后的代码进行额外优化。

内联技术

将方法的外部调用简化为在一个方法中调用,减少虚拟机栈的栈帧创建销毁的消耗。
例如:

publicintcalculate(){intx=10;inty=20;returnadd(x,y);// 这里发生了方法调用}// 被调用的小方法privateintadd(inta,intb){returna+b;}

优化为:

publicintcalculate(){intx=10;inty=20;returnx+y;}

如果方法过于臃肿(行数太长),则JIT会拒绝内联

如何从内联的角度理解阿里巴巴手册中规定的一个方法长度不能过长?

由于方法过于臃肿(行数太长)JIT会拒绝内联,如果这个方法是热点方法,其还是会被缓存,但是其没有被内联,使得其在执行其他方法(假设这个方法中调用了其他方法)的时候还是会去创建栈帧,销毁栈,使得执行效率低于内联之后的效率。

逃逸分析技术

标量替换+栈上分配

只有在使用C2编译器的时候(代码是热点代码),才会进行逃逸分析、标量替换等高级优化。

锁消除技术

对于加锁(synchronized),如果编译器发现锁本身只会被一个线程获取而不会被其他线程获取,那么JVM在编译的时候就会将锁去除,从而提高性能。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 10:37:49

10_C 语言进阶之避坑指南:浮点数与精度损失—— 不可思议的 “量化误差”

C 语言进阶之避坑指南:浮点数与精度损失—— 不可思议的 “量化误差” 浮点数是 C 语言中处理小数、科学计数法数值的核心类型,看似简单的float和double,却暗藏大量容易被忽视的陷阱 —— 从精度丢失导致的计算错误,到浮点数比较的逻辑漏洞,再到嵌入式环境下的浮点运算支…

作者头像 李华
网站建设 2026/9/2 21:29:42

通信系统仿真:通信系统基础理论_(2).信号与系统

信号与系统 信号的分类 在通信系统中,信号是信息传递的基本载体。根据不同的特性,信号可以分为多种类型。了解信号的分类是进行通信系统仿真和分析的基础。 连续时间信号与离散时间信号 连续时间信号是指在时间上连续变化的信号,可以用数学函数 x(t)x(t)x(t) 表示,其中…

作者头像 李华
网站建设 2026/9/2 2:36:00

网易Java面试被问:偏向锁在什么场景下反而降低性能?如何关闭?

偏向锁性能问题详解 一、偏向锁的工作原理与性能隐患 1. 偏向锁设计初衷 java // 偏向锁的核心思想:大多数情况下锁不存在竞争 public class BiasedLockDesign {/*假设场景:单线程重复获取同一把锁无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁偏…

作者头像 李华
网站建设 2026/9/2 16:12:03

【ros2】ROS2中激光雷达/IMU/深度相机配置与RViz可视化全指南

文章目录 激光雷达/IMU/深度相机配置与RViz可视化全指南 一、文档概述 二、前置准备 2.1 环境与依赖 2.2 功能包与目录结构 三、传感器配置步骤(URDF/Xacro) 3.1 激光雷达(LiDAR)配置 3.1.1 编写Xacro配置文件 3.1.2 关键参数说明 3.2 惯性测量单元(IMU)配置 3.2.1 在Xac…

作者头像 李华
网站建设 2026/9/2 0:15:50

Java 实现二叉搜索树:遍历、查询、构建

前言二叉搜索树&#xff08;Binary Search Tree&#xff0c;BST&#xff09;是数据结构中最基础且应用广泛的树形结构&#xff0c;其核心特性是「左子树所有节点值 < 根节点值 < 右子树所有节点值」&#xff0c;基于这一特性可实现高效的查找、插入和遍历操作。本文将从底…

作者头像 李华