JVM编译器

一、编译器

1. 前端编译器(javac)

把 .java → .class 字节码属于 编译期 ,只做语法解析、泛型擦除、语法糖解耦,不做运行期优化。

2. 后端即时编译器(JIT)

运行时把 字节码 → 机器码 属于 JVM 执行子系统 ,带运行期优化(逃逸分析、循环优化、锁消除等)。

二、JVM内置三大编译器

1. 解释器(Interpreter)

逐行解释执行字节码,不编译成机器码。

  • 启动快、省内存
  • 循环多、热点代码性能差

2. C1 编译器(Client 客户端编译器)

又叫 简单即时编译器

  • 编译速度快、优化保守
  • 适合桌面客户端、启动快优先
  • 做简单优化:常量折叠、方法内联

3. C2 编译器(Server 服务端编译器)

高性能编译器,面试重点

  • 编译稍慢,但优化极强
  • 服务端默认
  • 支持高阶优化:
    • 逃逸分析
    • 标量替换、栈上分配
    • 锁消除、锁粗化
    • 循环展开、循环无关外提

三、分层编译(JDK 默认)

解释器 + C1 + C2 配合工作

  1. 刚开始:解释器先跑,启动快
  2. 代码跑多了成为热点代码 → 交给 C1 编译
  3. 继续高频执行 → 升级 C2 深度优化

不用等全量编译,兼顾启动速度 + 运行高性能。

四、热点代码是什么

触发 JIT 编译的两类代码:

  1. 被多次调用的方法
  2. 被多次循环执行的循环体

由 计数器 统计热度,阈值到了就触发 JIT 编译优化。

五、JIT 编译器核心优化(必背)

1. 方法内联

(1) 什么是方法内联

把小方法的方法体代码 ,直接复制粘贴 到调用处,消除方法调用本身,不再走:调用 → 栈帧创建 → 参数传递 → 返回 → 栈帧销毁 这套流程。

通俗说:把小方法拆了,代码直接嵌进去用。

(2) 解决问题

  • 减少方法调用栈帧开销
  • 减少参数压栈、跳转、返回的性能损耗
  • 给后续其他优化创造前提(逃逸分析、标量替换、锁消除都依赖内联)

(3) 内联带来的连锁优化

方法内联之后,JVM 才能做:

  • 逃逸分析
  • 标量替换
  • 栈上分配
  • 锁消除
  • 常量传播、死代码消除

很多高级优化前提就是先做方法内联。

2. 逃逸分析

(1) 作用

分析一个对象的作用域 ,判断对象是否逃逸出当前方法、当前线程:

  • 不逃逸:对象只在方法内部使用
  • 逃逸:对象被返回、赋值给成员变量、被其他线程引用

(2) 未逃逸对象的3大核心优化

  • 栈上分配:对象没有逃逸,直接分配在栈上,方法结束自动销毁,不走 GC,极大减轻堆压力。
  • 标量替换:把对象拆解成一个个基本变量,不再创建整体对象,节省内存。
  • 同步消除:对象没有多线程共享逃逸,自动把 synchronized 锁消除,提升性能。

(3) 发生对象逃逸的情况

  • 对象作为方法返回值返回
  • 对象赋值给成员变量、静态变量
  • 对象传入多线程、线程池中使用
  • 对象被其他类引用持有

3. 锁消除

(1) 定义

某个锁对象没有逃逸 ,只在当前方法、当前线程内部使用,不存在多线程竞争,直接把 synchronized 锁给删掉,消除加锁解锁开销。

(2) 原理

  • 逃逸分析:判断锁对象是否只被当前线程访问,不对外逃逸;
  • 无共享、无竞争 → 虚拟机判定锁毫无意义;
  • JIT 编译时直接抹掉锁逻辑,变成普通代码执行。

4. 锁粗化

(1) 什么是锁粗化

如果连续多次对同一个对象反复加锁、解锁 ,JIT 会把多段小锁合并成一把大锁,减少频繁加解锁的开销。

(2) 触发场景

同一个锁对象,在连续代码块里频繁加解锁:

  • 循环里反复加锁
  • 连续调用同一个同步方法

(3) 和锁消除区别

  • 锁消除:根本没竞争,直接把锁删掉
  • 锁粗化 :锁必须保留,只是把多把小锁合并成一把,减少次数

5. 常量折叠

(1) 什么是常量折叠

编译期间直接把常量表达式算出最终结果,运行时不再重复计算。

通俗理解:代码里写死的常量加减乘除,编译器直接帮你算好结果,运行时直接用最终值。

(2) 适用场景

  • 基本数据类型常量运算:int、long、double、boolean
  • 字符串常量拼接

(3) 关键特点

  • 只针对常量,变量不参与折叠
  • 发生在 编译期,减轻运行时计算开销
  • 属于语法糖 + 编译优化
相关推荐
老三牛擦5 小时前
订单履约流程
jvm
青春逝如流水17 小时前
Java 线程在内存模型(JMM)与 JVM 实现:规范与落地的多元路径
java·开发语言·jvm·多线程·ai文章
colinu1 天前
C++ 异步任务与线程生命周期:`std::async`、`future`、`thread`、`jthread` 与协作式退出
java·jvm·c++
wuminyu1 天前
ForkJoinPool窃取线程在扫描其他WorkQueue时的随机采样算法与Phase线程挂起唤醒机制解析
java·linux·c语言·jvm·c++
DongQiShanRen1 天前
玄龙(上):TICK 主循环——意识心跳怎么跳
linux·jvm·数据库·人工智能·数据挖掘·rust
leisoo80971 天前
融资融券数据怎么查两融指标含义与杠杆观察方法 IG50免费开源股票数据API接口
开发语言·jvm·数据库·python·json
leisoo80972 天前
股票筹码分布怎么用获利比例成本区间与集中度实战 IG50免费开源股票数据API接口
开发语言·jvm·数据库·python·开源
晒太羊的猫2 天前
jvm面试题
jvm
夜之眷属2 天前
Core dump 崩溃排查:JVM 宕机后,那份 core 文件怎么用 gdb 还原现场
java·运维·服务器·jvm
用户094248568032 天前
第31章:JVM字节码解释器与模板解释器源码路径
java·jvm