---
title: OPcache・JIT が効くコード/効かないコードを、作って測って確かめる
tags: 
author: [_ma_me_](https://docswell.com/user/1313108)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/4EMYRLXVEW.jpg?width=480
description: OPcache・JIT が効くコード/効かないコードを、作って測って確かめる by _ma_me_
published: July 20, 26
canonical: https://docswell.com/s/1313108/ZY89PV-2026-07-20-005143
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/4EMYRLXVEW.jpg)

OPcache・JIT が
効くコード/効かないコードを、
作って測って確かめる
1


# Page. 2

![Page Image](https://bcdn.docswell.com/page/PER9RKNWJ9.jpg)

このセッションの目的
OPcache、JIT がそれぞれどこに効くのかを
計測して、数字で見て、理解する
パフォーマンス改善のヒントを
持ち帰ってもらえれば、幸いです
2


# Page. 3

![Page Image](https://bcdn.docswell.com/page/P7XQRLNVEX.jpg)

プロフィール
発表者
ma@me
所属
最近の業務
品質改善・不具合対応
3


# Page. 4

![Page Image](https://bcdn.docswell.com/page/37K9RLN57D.jpg)

1. OPcache の
効果計測
4


# Page. 5

![Page Image](https://bcdn.docswell.com/page/LJ3W83V1J5.jpg)

PHP の処理の流れ概要図
PHP ソース
コンパイル
OPCODE 生成
Zend VM で実行
5


# Page. 6

![Page Image](https://bcdn.docswell.com/page/8JDKM48KEG.jpg)

OPcache の効くところ
PHP ソース
2回目以降はスキップ
コンパイル
OPCODE 生成
① 保存
OPcache
メモリにキャッシュ
Zend VM で実行
6


# Page. 7

![Page Image](https://bcdn.docswell.com/page/VEPKRM8378.jpg)

OPcache の計測
まずは OPcache がどこに効いて
どこまで速くなるのか
作って・測って・確かめてみる
7


# Page. 8

![Page Image](https://bcdn.docswell.com/page/27VVR9NN7Q.jpg)

計測環境
実行基盤
ネイティブ x86_64
（GitHub Actions ubuntu-latest）
PHP
8.5
フレームワーク
Laravel 13.14
計測ライブラリ
PHPBench 1.7
8


# Page. 9

![Page Image](https://bcdn.docswell.com/page/5JGLMZK57L.jpg)

OPcache の効くところはシンプル
効果はコード量（コンパイル対象の規模）
にほぼ比例
↑ 効果あり：大量のクラス/ファイル
↓ 効果なし or 薄い：薄いスクリプト群
9


# Page. 10

![Page Image](https://bcdn.docswell.com/page/47QYRLNLEP.jpg)

Laravel で効果を計測する
対象
Laravel の初期 Welcome ページを表示
条件
OPcache OFF / ON で、それぞれ 30 回ずつリクエスト
計測値
1 リクエストのブート時間
10


# Page. 11

![Page Image](https://bcdn.docswell.com/page/KE4W8DG5J1.jpg)

Laravel 計測結果
500 ファイル / リクエストを読み込み
OPcache
平均 / 1リクエスト
OFF との比較
OFF
68.71 ms
ー
ON
42.43 ms
約 26 ms 短縮
5000ファイル
OPcache
平均 / 1リクエスト
OFF との比較
OFF
83.142 ms
ー
ON
10.112 ms
約 70 ms 短縮
11


# Page. 12

![Page Image](https://bcdn.docswell.com/page/L71Y2ZD2JG.jpg)

読み込みファイルが多いほど 効果：大
⤴︎
ファイル数が多くなる、フレームワークと相性抜群
12


# Page. 13

![Page Image](https://bcdn.docswell.com/page/G7WGR9Y2E2.jpg)

注意点：キャッシュ領域を
ちゃんと取ってあげる
キャッシュ領域が足りないと性能がダウンする
設定
計測値
差分
OFF
83.142 ms
ー
ON（8MB。不足）
61.680 ms
基準より約 20ms UP
24MB より約 50 msダウン
ON（32MB）
10.112 ms
基準より約 70ms UP
24MB より約 50 msアップ
13


# Page. 14

![Page Image](https://bcdn.docswell.com/page/4JZLR9X4E3.jpg)

逆効果パターン
ファイル数が多くても、関数 1 個だけの極小ファイルを
大量に読み込むケースでは逆効果
require &quot;1.php&quot;;
require &quot;2.php&quot;;
・・・
14


# Page. 15

![Page Image](https://bcdn.docswell.com/page/YE6WRK4GEV.jpg)

薄いスクリプト計測結果
全条件で OPcache ON の方が遅い。
キャッシュ作成コストが上回ったパターン。
関数 1 個だけの PHP ファイルを50個読み込み
require数
OPcache OFF
OPcache ON
差（ON − OFF）
1
0.039 ms
0.070 ms
+0.031 ms
50
0.719 ms
1.000 ms
+0.281 ms
500
7.033 ms
12.453 ms
+5.420 ms
15


# Page. 16

![Page Image](https://bcdn.docswell.com/page/GE5M8PQXE4.jpg)

設定値で気をつけること
OWeb アプリケーション：Opcache は初期設定で ON
CLI実行：Opcache は初期設定で OFF
このような実行形式には無効になっている
php artisan queue:work
16


# Page. 17

![Page Image](https://bcdn.docswell.com/page/9729K6PQJR.jpg)

Laravelなど フレームワークを使った開発であれば
恩恵に預かれる。
デフォルト ON なので、よっぽどなことでない限り OFF に
しない
17


# Page. 18

![Page Image](https://bcdn.docswell.com/page/DJY4N95Y7M.jpg)

2. JIT の効果計測
18


# Page. 19

![Page Image](https://bcdn.docswell.com/page/V7NYXLNRE8.jpg)

JIT（Just-in-Time） の概要
PHP には Opchache と PCRE にそれぞれ備え付けられている
必要なものを、必要な時に、必要なだけ作る
＝必要でなければ作られない
キャッシュした OPCODE を
ネイティブ機械語に変換して実行
Zend VM を介さず CPU が直接走るため
計算ヘビーな処理ほど効きやすい
19


# Page. 20

![Page Image](https://bcdn.docswell.com/page/YJ9P84RZ73.jpg)

JIT が導入された目的
PHP コードを機械語化し、実行コストを下げる。
特に、計算負荷の高い処理を高速化する。
Web 以外の CPU 集約用途 へ、PHP を広げる。
参考：JIT のプロポーザル https://wiki.php.net/rfc/jit
20


# Page. 21

![Page Image](https://bcdn.docswell.com/page/GJ8D8QGYJD.jpg)

CPU アーキテクチャごとに
分かれる実装
x86（32-bit / i386）
x86_64（今回使用）（64-bit / AMD64）
ARM64（AArch64 / Apple Silicon 等）
同じコードでも結果に差異が出るので
JIT の計測をするときは要注意
21


# Page. 22

![Page Image](https://bcdn.docswell.com/page/LJLMRXG9ER.jpg)

function と tracing
function
関数全体をひとまとまりとして、機械語へコンパイル
tracing
実行時に頻繁に通る経路を見つけ、
トレース単位でコンパイル
前述した CPU アーキテクチャでは特に差が出た部分
ARM64 では
function が tracing より遅くなる傾向がありました
(スペースの都合上、結果は載せていません)
22


# Page. 23

![Page Image](https://bcdn.docswell.com/page/47MYRLQV7W.jpg)

JIT は Web 開発でも効果的なのか？
標準関数にどこまで作用するのか
計測していきます
23


# Page. 24

![Page Image](https://bcdn.docswell.com/page/P7R9RK8WE9.jpg)

JIT の計測環境
CPU / アーキ
ネイティブ x86_64
（GitHub Actions ubuntu-latest ）
PHP
8.5（OPcache 前提）
JIT モード
OFF / function / tracing
（ jit_buffer_size = 0 / 64M）
計測ライブラリ
PHPBench
24


# Page. 25

![Page Image](https://bcdn.docswell.com/page/PJXQRL8V7X.jpg)

OPchace.JIT が効く箇所
PHP ソース
2回⽬以降はスキップ
コンパイル
OPCODE ⽣成
Zend VM で実⾏
① 保存
OPcache
メモリにキャッシュ
JIT 経路
JIT
OPCODE → 機械語
CPU が直接
機械語を実⾏
25


# Page. 26

![Page Image](https://bcdn.docswell.com/page/3JK9RLK5JD.jpg)

JIT で isset と in_array() 速度差は縮
まるのか
// in_array：値の中から探す（得意：値検索）
$values = range(1, 10000);
in_array(10000, $values, true);
// 末尾までフルスキャン
// isset：キーの有無を引く（得意：キー参照）
$keys = array_fill_keys(range(1, 10000), true);
isset($keys[10000]);
// 1 回のハッシュ参照
26


# Page. 27

![Page Image](https://bcdn.docswell.com/page/LE3W83Z1E5.jpg)

計測結果：ホットループ
1計測関数 = 対象処理を1万回実行
処理
JIT OFF
function
tracing
１回あたり
in_array
78,788.0μs
78,139.1μs
78,271.6μs
7,878.8 / 7,813.9 ns
isset
27.6μs
27.4μs
27.3μs
3.8 / 0.2 ns
array_key_exists
53.7μs
62.6μs
61.2μs
6.3 / 5.4 ns
１回あたり：最大値 / 最小値
ほぼ変わらない...?
array_key_exists に関しては悪化傾向に
27


# Page. 28

![Page Image](https://bcdn.docswell.com/page/8EDKM4RK7G.jpg)

標準関数の呼び出しフロー
コンパイル
PHP コード
in_array(...)
実行
C 関数を呼ぶ
Zend VM /
C 実装の標準関数
JIT 生成コード
検索・比較などを実行
JIT ON で最適化される範囲
JIT の対象外
関数呼び出し
OPCODE
C 実装の本体処理は、JIT ON / OFF で変わらない
計算量が絡むのは C 実装側で JIT の対象外
JIT では標準関数の速度差を縮められない。
効果がないのか？
28


# Page. 29

![Page Image](https://bcdn.docswell.com/page/V7PKRMW3J8.jpg)

JIT の恩恵を受ける標準関数群
一部の関数は JIT の恩恵を受ける
1. コールバックを受け取る関数群
2. 専用 OPECODE を持つ関数
3. 正規表現を使う検索、置換関数
29


# Page. 30

![Page Image](https://bcdn.docswell.com/page/2JVVR98NJQ.jpg)

1. コールバックを受け取る
関数群
array_map, usort() などの
コールバックを受け付ける関数は
コールバック部分が JIT の効果を受ける
function array_map(
?callable $callback,
array $array,
array ...$arrays
): array
30


# Page. 31

![Page Image](https://bcdn.docswell.com/page/5EGLMZ55JL.jpg)

計測結果：コールバック関数
1計測関数 = array_map / usort を10,000回実行
処理
JIT OFF
function
tracing
１関数あたり
array_map
3,727.9μs
2,927.4μs
2,939.9μs
372.8 / 292.7 ns
usort
18,097.4μs
15,293.7μs
15,297.0μs
1,809.7 / 1,529.4 ns
１関数あたり：最大値 / 最小値
約 1.18〜1.27 倍高速
31


# Page. 32

![Page Image](https://bcdn.docswell.com/page/4JQYRLZL7P.jpg)

2. 専用 OPCODE を持つ関数
一部、専用の OPCODE を持つ関数がある
実行コスト&gt; 関数呼び出し の場合
専用 OPCODE が用意されている
ZEND_STRLEN（strlen）
ZEND_COUNT（count）
ZEND_TYPE_CHECK（is_int / is_string 等）
32


# Page. 33

![Page Image](https://bcdn.docswell.com/page/K74W8D35E1.jpg)

計測結果：strlen / count
1計測関数 = それぞれの関数をを10,000回実行
呼び方
JIT OFF
function
tracing
１関数あたり
strlen（裸）
148.4μs
86.9μs
87.5μs
14.8 / 8.7 ns
\strlen
40.3μs
30.0μs
30.3μs
4.0 / 3.0 ns
count（裸）
136.0μs
76.5μs
77.1μs
13.6 / 7.7 ns
\count
34.9μs
23.0μs
23.6μs
3.5 / 2.3 ns
33


# Page. 34

![Page Image](https://bcdn.docswell.com/page/LJ1Y2Z12EG.jpg)

なぜ
\ を付けると速いのか
\ の有無で自作関数かグローバル関数かが決まる
グローバル関数と分かれば、その分実行が早い
strlen($s)
\strlen($s)
ユーザー作の strlen かも？
グローバル関数と確定
専用 OPCODE 化できない
ZEND_STRLEN へ置換
34


# Page. 35

![Page Image](https://bcdn.docswell.com/page/GJWGR98272.jpg)

3. 正規表現を使う
検索、置換関数
opcache.jit 以外のもう１つの JIT
pcre.jit
正規表現パターンをネイティブ化する
https://www.php.net/manual/ja/pcre.configuration.php
preg_match(), preg_match_all() などの関数が
恩恵を受ける
35


# Page. 36

![Page Image](https://bcdn.docswell.com/page/4EZLR98473.jpg)

計測結果：PCRE JIT
1計測関数 = preg_* を10,000回実行
処理
PCRE JIT OFF
PCRE JIT ON
１回あたり
preg_match
190.228ms
23.524ms
19.0 / 2.4 μs
preg_match_all
307.039ms
37.144ms
30.7 / 3.7 μs
preg_replace_callback
302.597ms
39.270ms
30.3 / 3.9 μs
１回あたり：最大値 / 最小値
PCRE JIT で約 7.7〜8.3 倍高速
36


# Page. 37

![Page Image](https://bcdn.docswell.com/page/Y76WRKPG7V.jpg)

標準関数でも JIT の
効果はある。。。?!
37


# Page. 38

![Page Image](https://bcdn.docswell.com/page/G75M8PKX74.jpg)

ここで時間の単位の確認
秒（s）を基準にした大きさ
単位
記号
1秒の何分の1
換算
秒
s
1
1s = 1,000ms
ミリ秒
ms
1 / 1,000
1ms = 1,000μs
マイクロ秒
μs
1 / 1,000,000
1μs = 1,000ns
ナノ秒
ns
1 / 1,000,000,000
—
38


# Page. 39

![Page Image](https://bcdn.docswell.com/page/9J29K6WQER.jpg)

時間の単位と比べてみる、strlenの改善効果
呼び方
JIT OFF
function
tracing
１関数あたり
strlen（裸）
148.4μs
86.9μs
87.5μs
14.8 / 8.7 ns
\strlen
40.3μs
30.0μs
30.3μs
4.0 / 3.0 ns
単位
記号
1秒の何分の1
換算
秒
s
1
1s = 1,000ms
ミリ秒
ms
1 / 1,000
1ms = 1,000μs
マイクロ秒
μs
1 / 1,000,000
1μs = 1,000ns
ナノ秒
ns
1 / 1,000,000,000
—
39


# Page. 40

![Page Image](https://bcdn.docswell.com/page/DEY4N9LYJM.jpg)

正直、体感するのは難しいくらいの効果。。。
実行回数が少なければ、より効果は少ない
40


# Page. 41

![Page Image](https://bcdn.docswell.com/page/VJNYXL4R78.jpg)

ユーザー定義コードの計測
とはいえ、普段書くコードではどうなのか？
どこまで JIT の効果がでるのかを計測していきます
・四則演算
・ループ
・条件判定
41


# Page. 42

![Page Image](https://bcdn.docswell.com/page/YE9P84QZJ3.jpg)

四則演算の計測
$value = 0.0;
for ($i = 0; $i &lt; 10000; $i++) {
$value += 1.0001;
}
42


# Page. 43

![Page Image](https://bcdn.docswell.com/page/GE8D8QQYED.jpg)

計測結果
1関数 = 1万回の演算
処理
JIT OFF
function
tracing
１演算あたり
加算（+）
42.756μs
11.311μs
11.240μs
4.3 / 1.1 ns
減算（−）
42.619μs
11.364μs
11.301μs
4.3 / 1.1 ns
乗算（×）
42.461μs
11.321μs
11.333μs
4.2 / 1.1 ns
浮動小数点除算
85.217μs
88.022μs
88.333μs
8.8 / 8.5 ns
整数除算
145.210μs
89.204μs
89.139μs
14.5 / 8.9 ns
１演算あたり：最大値 / 最小値（ループ込み）
43


# Page. 44

![Page Image](https://bcdn.docswell.com/page/LELMRXX97R.jpg)

加減乗は JIT で約 3.7〜3.8 倍高速
一方、除算は JIT を有効にしても、CPU の演算コストが上回り、
遅くなる結果に
いろんなパターンを試すも、除算は安定せず...
44


# Page. 45

![Page Image](https://bcdn.docswell.com/page/4JMYRLLVJW.jpg)

ループ制御の計測
純粋なループを計測するために本体処理は空
for ($i = 0; $i &lt; self::N; $i++) {}
foreach ($this-&gt;loopValues as $_) {}
45


# Page. 46

![Page Image](https://bcdn.docswell.com/page/PJR9RKKW79.jpg)

計測結果
for は約 6 倍、foreach は約 1.9 倍高速
1計測関数 = 10,000ループ
処理
JIT OFF
JIT function
JIT tracing
１ループあたり
for
29.426μs
4.841μs
4.856μs
2.9 / 0.5 ns
foreach
39.305μs
20.746μs
20.931μs
3.9 / 2.1 ns
１ループあたり：最大値 / 最小値
46


# Page. 47

![Page Image](https://bcdn.docswell.com/page/PEXQRLLVJX.jpg)

単純比較にも JIT は効く
1万回分（基準処理差引後の推定値）
判定
JIT OFF
function
tracing
１回あたり
単純 if ==
61.3μs
32.7μs
34.2μs
6.1 / 3.3 ns
単純 if ===
15.6μs
3.4μs
4.8μs
1.6 / 0.3 ns
単純 switch
81.9μs
41.2μs
42.3μs
8.2 / 4.1 ns
単純 match
23.3μs
2.8μs
3.5μs
2.3 / 0.3 ns
計算結果 if
44.1μs
9.6μs
7.6μs
4.4 / 0.8 ns
計算結果 switch
37.5μs
7.6μs
7.5μs
3.8 / 0.8 ns
計算結果 match
107.2μs
85.9μs
86.0μs
10.7 / 8.6 ns
１回あたり：最大値 / 最小値
47


# Page. 48

![Page Image](https://bcdn.docswell.com/page/3EK9RLL5ED.jpg)

効果があるとはいえ、μs（マイクロ秒）の改善で
まだ効果が厳しい...!
そもそもの処理が早いのもある。これは PHP7 以降の改善が
素晴らしい
👏
48


# Page. 49

![Page Image](https://bcdn.docswell.com/page/L73W833175.jpg)

クラスを定義して計測
より実践的に、クラスを定義してコードの計測
final class Money {
public function __construct( private readonly int $amount) {}
public function add(Money $o): self { return new self($this-&gt;amount + $o-&gt;amount); }
public function multiply(int $f): self { return new self($this-&gt;amount * $f); }
}
より実践的なコードでその効きの差を検証
お題は、クーポン割引・送料計算
49


# Page. 50

![Page Image](https://bcdn.docswell.com/page/87DKM44KJG.jpg)

題材：クーポン割引・送料計算
1
小計 カート明細（単価 × 数量）を合計する
2
割引 適用クーポンで割引額を算出する（定額 / 率 / 条件付き）
3
送料 配送地域 × 重量から送料を算出する（無料ライン判定あり）
4
確定 小計 − 割引 ＋ 送料 で請求額を確定する
50


# Page. 51

![Page Image](https://bcdn.docswell.com/page/VJPKRMM3E8.jpg)

ベースの実装概要
ミュータブル版は new せず、
代入したオブジェクトを返す
// クーポンは interface ＋ 3 実装（定額 / 率 / 条件付き）
interface Coupon { function discountFor(Money $s): Money; }
// 小計 → 割引 → 送料 → 確定（Money は演算のたびに new）
$discount
= $cart-&gt;coupon-&gt;discountFor($subtotal); // ← new
$discounted = $subtotal-&gt;subtract($discount);
// ← new
$total
= $discounted-&gt;add($shipping);
// ← new
51


# Page. 52

![Page Image](https://bcdn.docswell.com/page/2EVVR99NEQ.jpg)

計測結果
1計測関数 = カート確定を10,000件実行
実装
JIT OFF
function
tracing
１件あたり
イミュータブル
18.61ms
12.27ms
12.34ms
1,861.5 / 1,226.7 ns
ミュータブル
5.77ms
2.35ms
2.37ms
576.8 / 235.4 ns
１件あたり：最大値 / 最小値
JIT で イミュータブルは約 6ms
イミュータブルは約 3ms の削減
52


# Page. 53

![Page Image](https://bcdn.docswell.com/page/57GLMZZ5EL.jpg)

ここまでの計測結果を
踏まえての感想
OPchache.jit は無理に適用しなくてもいいかなー。。。
色々な設定値を変えても、
ns レベルの変化しかなかった or 遅くなってしまった...
53


# Page. 54

![Page Image](https://bcdn.docswell.com/page/4EQYRLLLJP.jpg)

OPcache, JIT の計測を
終えての感想
このような設定値になっていれば理想
効果の高かった Opcache：ON
一番効果の高かった正規表現の PCRE.JIT：ON
使い所の難しい Opcache.JIT：OFF
54


# Page. 55

![Page Image](https://bcdn.docswell.com/page/KJ4W8DD571.jpg)

PHP の
OPcache / JIT の既定値
Opcache：ON
正規表現 PCRE.JIT：ON
Opcache.JIT：OFF
55


# Page. 56

![Page Image](https://bcdn.docswell.com/page/LE1Y2ZZ27G.jpg)

すでになっていました。
デフォルトが最適!
PHP 公式ありがとう...!
56


# Page. 57

![Page Image](https://bcdn.docswell.com/page/GEWGR992J2.jpg)

ご清聴
ありがとうございました
57


