Bohr-L Bohr-L
首页
技术
常见面试题
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

刘博

I'm a slow walker, But I never walk backwards.
首页
技术
常见面试题
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 数据处理与存储类

  • Spring 生态类

  • 缓存问题类

  • 多线程类

  • JVM 类

    • JVM 中一次完整的 GC 流程(从 ygc 到 fgc)是怎样的
    • 如何判断对象可以被回收
    • 你知道哪些垃圾收集算法
    • 虚拟机为什么使用元空间替换了永久代
    • 简述 CMS 垃圾收集器的工作流程,它有什么优缺点?
    • 简述一下 JVM 的内存模型
    • 说说堆和栈的区别
    • 简述 Java 的对象结构
    • JVM 中的即时编译器(JIT)如何工作?
      • 什么是内存屏障?JVM 如何使用内存屏障保证指令执行顺序?
      • 如何排查和解决 JVM 内存泄漏问题?有哪些常用的工具和方法?
      • JVM 如何处理异常?try-catch-finally 结构在字节码层面是如何实现的?
    • MySQL 类

    • Java 8 + 特性类

    • 其他技术类

    • 常见面试题
    • JVM 类
    刘博
    2025-12-28
    目录

    JVM 中的即时编译器(JIT)如何工作?

    JIT(Just-In-Time Compiler,即时编译器)是 JVM 中 “将字节码转换为本地机器码” 的核心组件,目的是提升 Java 程序的执行效率(字节码需通过解释器逐行执行,效率低;本地机器码可直接被 CPU 执行,效率高),工作流程如下:

    # 1. JIT 的触发条件:热点代码识别

    JVM 通过 “热点探测” 识别 “热点代码”(被频繁执行的代码),仅对热点代码触发 JIT 编译,避免资源浪费,热点探测的核心指标是 “方法调用次数” 和 “循环执行次数”:

    • (1)基于计数器的热点探测(HotSpot JVM 采用):
      • 每个方法对应两个计数器:方法调用计数器(记录方法被调用的次数)和回边计数器(记录方法中循环的执行次数,“回边” 指循环跳转指令);
      • 当方法调用计数器超过-XX:CompileThreshold(默认 10000 次,C1 编译器)或回边计数器超过阈值时,JVM 标记该方法为 “热点代码”,触发 JIT 编译。

    # 2. JIT 的编译流程

    JIT 编译分为 “前端编译” 和 “后端编译”,最终生成优化后的本地机器码:

    • (1)前端编译:
      • 输入:热点代码的字节码;
      • 步骤:
        1. 词法分析:将字节码指令拆分为 Token(如操作码、操作数);
        2. 语法分析:将 Token 组合为抽象语法树(AST),描述代码的逻辑结构;
        3. 语义分析:检查语法树的合法性(如类型匹配、变量未定义),并进行初步优化(如常量折叠,1+2优化为3)。
    • (2)后端编译:
      • 步骤:
        1. 中间代码生成:将抽象语法树转换为中间表示(IR,如 HotSpot 的 HIR、LIR),便于跨平台优化;
        2. 优化阶段:对中间表示进行多层优化,提升代码执行效率,常见优化手段:
          • 方法内联:将被调用的小方法(如getter/setter)直接嵌入调用者代码,减少方法调用开销;
          • 循环优化:循环展开(减少循环跳转次数)、循环不变量外提(将循环内不变的计算移到循环外);
          • 逃逸分析:判断对象是否 “逃逸”(是否被方法外引用),若未逃逸,可进行栈上分配(避免堆内存 GC)、标量替换(将对象拆分为局部变量);
          • 公共子表达式消除:若多个地方计算相同的表达式(如a+b),仅计算一次并复用结果;
        3. 机器码生成:将优化后的中间表示转换为目标 CPU 的本地机器码(如 x86、ARM 架构),并存储在 “代码缓存”(Code Cache)中。

    # 3. JIT 的编译模式:C1 与 C2 编译器(分层编译)

    HotSpot JVM 提供两种 JIT 编译器,采用 “分层编译”(Tiered Compilation)模式,平衡编译速度和执行效率:

    • C1 编译器(Client Compiler,客户端编译器):
      • 特点:编译速度快,优化程度低,适合桌面应用(如 GUI 程序);
      • 适用场景:代码刚被标记为热点时,先由 C1 编译,快速生成可执行的机器码,避免程序等待;
    • C2 编译器(Server Compiler,服务端编译器):
      • 特点:编译速度慢,优化程度高(支持更多高级优化,如逃逸分析、向量化),适合服务器应用(如 Java Web 服务);
      • 适用场景:当代码被 C1 编译后仍被频繁执行,触发 C2 编译,生成更高效的机器码,替换 C1 编译的结果;
    • 分层编译流程:
      1. 代码初始执行时,由解释器逐行执行;
      2. 代码被标记为热点后,触发 C1 编译,生成基础优化的机器码;
      3. 代码持续被频繁执行,触发 C2 编译,生成深度优化的机器码;
      4. 后续执行时,直接调用代码缓存中的 C2 机器码,效率最大化。

    # 4. JIT 的代码缓存(Code Cache)

    • 作用:存储 JIT 编译生成的本地机器码,避免重复编译;
    • 配置:通过-XX:InitialCodeCacheSize(初始大小)和-XX:ReservedCodeCacheSize(最大大小,默认 240MB)配置;
    • 回收:当代码缓存满时,JVM 会清理 “不常用的机器码”(如长时间未执行的热点代码),释放空间。

    上次更新: 12/30/2025
    简述 Java 的对象结构
    什么是内存屏障?JVM 如何使用内存屏障保证指令执行顺序?

    ← 简述 Java 的对象结构 什么是内存屏障?JVM 如何使用内存屏障保证指令执行顺序?→

    最近更新
    01
    CPU 使用率较高排查和解决
    12-29
    02
    JVM OOM 问题如何排查和解决
    12-29
    03
    接口防刷怎么实现?
    12-29
    更多文章>
    Theme by Vdoing | Copyright © 2025-2026 Bohr-L's note
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式