JIT 是什么 ? JIT在PHP8中是如何工作的?

Just-In-Time即时编译器是PHP 8.0中最重要的新功能之一。JIT可以通过将PHP应用程序的全部或经常调用的部分作为CPU机器代码编译并存储并直接执行,从而绕过Zend VM及其过程开销,从而提高性能。

但它也增加了调试的障碍,因为应用程序的某些部分可能作为CPU机器代码缓存,而标准PHP调试器无法使用。PHP 8.0的JIT pull-request在PHP代码库中增加了50,000多个新行,因此,除了从事JIT的开发人员之外,PHP核心开发人员本身可能并不精通。

JIT是传统解释器和AOT编译器的混合体。混合模型带来了这两种方法的利弊,而经过微调的应用程序可以胜过JIT的弊端。

大多数PHP应用程序都接受HTTP请求,从数据库中检索和处理数据,并返回结果。IO通常是重要的性能瓶颈:从磁盘读取数据,写入和网络请求。

什么是 JIT?

JIT 是 Just-In-Time 编译的缩写,是一种在运行时将高级源代码编译成机器码的技术。传统的 PHP 解释器将 PHP 源代码逐行解释执行,而 JIT 编译器将 PHP 源代码在运行时编译成机器码,然后执行编译后的机器码,从而提高了执行效率。

JIT 在 PHP 8 中的引入

在 PHP 8 中,JIT 编译器是一个全新的 Zend 引擎特性。这个功能的目标是通过编译和缓存热代码路径来提高 PHP 脚本的性能。PHP 8 的 JIT 编译器可以显著加快 PHP 应用程序的执行速度,特别是对于 CPU 密集型的任务。

JIT 编译器的工作原理

JIT 编译器的核心思想是将 PHP 源代码分为热代码路径和冷代码路径。热代码路径是那些在运行时频繁执行的代码块,而冷代码路径是相对不常执行的代码块。

以下是 JIT 编译器在 PHP 8 中的工作原理:

  1. 热代码路径识别
    在 PHP 脚本的执行过程中,Zend 引擎会跟踪哪些代码块被频繁执行。这些热代码路径会被标记以备编译。
  2. 代码分析和优化
    热代码路径中的 PHP 源代码将被 JIT 编译器分析和优化。这个过程包括对代码进行类型推断和更好的代码生成。
  3. 机器码生成
    一旦代码经过分析和优化,JIT 编译器将生成相应的机器码。
  4. 机器码缓存
    生成的机器码被缓存以备将来使用,这样在下次执行相同的代码路径时,无需再次编译。
  5. 执行机器码
    一旦机器码被缓存,PHP 脚本的执行将切换到执行机器码而不是解释 PHP 源代码,从而实现性能提升。

JIT 在 PHP 8 中的配置

在 PHP 8 中,你可以通过配置来启用或禁用 JIT 编译器以及调整其行为。以下是一些与 JIT 相关的配置选项:

  • opcache.jit:这是 JIT 编译器的主要配置选项。你可以设置为 "tracing"(默认值)以启用 JIT 编译器,或设置为 "off" 以禁用 JIT 编译器。
  • opcache.jit_buffer_size:用于配置 JIT 编译缓冲区的大小。
  • opcache.jit_debug:用于启用或禁用 JIT 编译器的调试模式,以帮助诊断性能问题。

示例:启用 JIT 编译器

以下是一个示例代码,演示如何在 PHP 8 中启用 JIT 编译器以加速 PHP 脚本的执行。创建一个 PHP 脚本,例如 jit_example.php,并添加以下内容:

php 复制代码
<?php

ini_set('opcache.jit', 'tracing');

function fibonacci($n) {
    if ($n <= 1) {
        return $n;
    } else {
        return fibonacci($n - 1) + fibonacci($n - 2);
    }
}

$start = microtime(true);
$result = fibonacci(35);
$end = microtime(true);
$elapsed = $end - $start;

echo "Fibonacci result: $result\n";
echo "Elapsed time: $elapsed seconds\n";

在这个示例中,我们启用了 JIT 编译器,然后定义了一个递归的 Fibonacci 函数来测试性能。运行这个脚本并观察输出,你将看到 JIT 编译器在编译和执行代码时的影响。

Function JIT

相比之下,Function JIT模式是一个相当简单的模式。它通过JIT编译整个函数,而无需跟踪常用的代码结构,例如函数内部的循环。它仍然支持对常用函数进行性能分析,并在执行应用程序请求之前,之后或期间触发JIT编译或编译后的机器代码的执行。

Tracing JIT

Tracing JIT(在PHP 8.0中默认选择)试图识别经常使用的代码部分,并选择性地编译这些结构,以在编译时间和内存使用之间取得最佳平衡。并非所有的编程语言都支持tracing JIT编译器,但是PHP支持从第一个发行版开始就支持tracing JIT,并且默认情况下也是选中的。

有几个配置选项可以进一步调整如何确定热代码结构,例如函数调用的次数,循环结构的迭代次数等。

分析和优化

JIT可以在代码运行时对其进行检查,分析和优化。PHP JIT提供了对阈值和触发器的细粒度控制,其中涉及多少调用使其成为将JIT编译为机器代码的合适候选者,并且可以使用新编译的代码。如果在缓冲区中也存在后续的请求,则可以使用编译后的代码。

JIT友好代码

当JIT可以尽可能多地分流到本机CPU寄存器和指令时,它将受益匪浅。PHP是一种弱类型的语言,这使得很难推断变量的类型,并且需要对变量的生命周期进行更多分析,因为变量的类型可能在同一代码结构的稍后位置发生变化。

严格类型的代码以及具有标量类型的函数可以帮助JIT推断类型,并在可能的情况下利用CPU寄存器和专用指令。例如,一个纯函数(没有副作用),启用严格类型并带有参数和返回类型可能是理想的选择:

bash 复制代码
declare(strict_types=1);

function sum(float $a, float $b): float {
    return $a + $b;
}

当PHP无法推断类型时,它可能无法充分利用JIT优化。

实际上,PHP 7的一些改进来自这些优化,它们可以消除无效代码并改善引用计数。这意味着更严格类型化的代码为PHP提供了更多机会来优化Opcache级别和JIT级别的代码。

基本的JIT配置

默认情况下,JIT是启用的,但可通过限制缓冲区大小将其关闭。

最简单的设置是简单地为JIT设置缓冲区大小,然后JIT将使用合理的默认值。

ini 复制代码
opcache.enable=1
opcache.enable_cli=1
opcache.jit_buffer_size=256M
相关推荐
空山返景4 分钟前
Dify RAG知识库-自部署完整指南
后端
苏三的开发日记22 分钟前
如何规避死锁
后端
该用户已不存在24 分钟前
用 Claude Code Agents 与 CI/CD 搭建自动化研发团队(Part 3)
后端·ai编程·claude
豹哥学前端27 分钟前
agent智能体经典范式构建
人工智能·后端
胡志辉1 小时前
邮件中点击“加载图片”,你的IP地址已经被泄漏
前端·后端·安全
拽着尾巴的鱼儿2 小时前
spring 动态代理
java·后端·spring
Rust研习社2 小时前
Rust 的 move 语义,一次讲透
后端·rust·编程语言
IT_陈寒2 小时前
用了Vue的动态组件之后,我被坑得找不着北
前端·人工智能·后端
undefinedType2 小时前
深入理解 Rails includes:为什么一个 order(users.xxx) 会导致超级 JOIN 性能问题
后端
baviya3 小时前
用 Spring AI Alibaba JManus 构建零售智能客服工单系统:从 0 到日处理 10 万单
后端·ai编程