0Pricing
PHP Academy · レッスン

OPcacheとJITコンパイル

バイトコードキャッシュとJITでPHPを高速化します。

「OPcacheとJITコンパイル」はCoddyKit上の無料PHP Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPHP Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 PHP Academyコースには全4レッスンが含まれています。

コンパイル結果のキャッシュ

OPcacheはコンパイル済みオペコードを共有メモリに保存し、PHPがリクエストごとに字句解析、構文解析、コンパイルを行わずに済むようにします。さらに、JIT(PHP 8.0以降)はホットなオペコードをネイティブマシンコードにコンパイルします。これらは合わせて、PHPのパフォーマンスを支える中核です。

このレッスンでは、OPcacheの設定、プリロード、JITのチューニングについて学びます。

OPcacheの役割

各ファイルのコンパイル済みop_arrayは、すべてのFPMワーカーが使用する共有メモリセグメントにキャッシュされます。キャッシュにヒットしたリクエストは、オペコードを直接再利用します。OPcacheは、ファイルを初めてコンパイルするときに、オプティマイザ(定数畳み込み、デッドコード削除、オペコード融合)も実行します。

; Core OPcache config (php.ini)
opcache.enable = 1
opcache.memory_consumption = 256      ; MB of shared memory
opcache.interned_strings_buffer = 16  ; MB for interned strings
opcache.max_accelerated_files = 20000 ; cap on cached scripts

タイムスタンプ検証

validate_timestampsは、OPcacheがファイルのmtimeを再確認するかどうかを決定します。開発環境では有効にし、revalidate_freqを短くしてください。本番環境では0に設定してPHPがファイルのstatを行わないようにし、キャッシュをクリアするかイメージを再構築してデプロイしてください。

; Production: never re-stat files
opcache.validate_timestamps = 0

; Development: check every 2 seconds
; opcache.validate_timestamps = 1
; opcache.revalidate_freq = 2

キャッシュの確認

opcache_get_status()は、ヒット率、メモリ使用量、キャッシュされたスクリプトを報告します。opcache_get_configuration()では設定を確認できます。ヒット率が低い、または再起動が頻繁に発生する場合は、メモリが少なすぎるか、ファイルが多すぎる可能性があります。

<?php
if (function_exists('opcache_get_status')) {
    $s = opcache_get_status(false);
    if ($s) {
        printf("hits:   %d\n", $s['opcache_statistics']['hits']);
        printf("misses: %d\n", $s['opcache_statistics']['misses']);
        printf("hit %%: %.2f\n", $s['opcache_statistics']['opcache_hit_rate']);
        printf("used:   %.1f MB\n", $s['memory_usage']['used_memory'] / 1048576);
    } else {
        echo "OPcache enabled but no status (likely CLI)\n";
    }
} else {
    echo "OPcache not available\n";
}
?>

プリロード

プリロード(PHP 7.4以降)は、サーバー起動時にクラスと関数の集合を1度だけコンパイルし、それらを永続的にメモリに保持します。すべてのリクエストから、オートロードやリクエストごとのリンク処理なしで利用できます。opcache.preloadに、ウォームアップするファイルをrequireするスクリプトを指定してください。

; php.ini
opcache.preload = /app/preload.php
opcache.preload_user = www-data

プリロードスクリプトの作成

プリロードスクリプトはマスタープロセスで実行されます。opcache_compile_file()を使うと、実行せずにクラスを読み込めます。単にrequireすることもできます。フレームワークはプリロードリストを生成します。以下はその形式です。

<?php
// preload.php — runs once at startup
$dir = '/app/src';
$rii = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($dir)
);

foreach ($rii as $file) {
    if ($file->getExtension() === 'php') {
        // Compiles + links the class into shared memory
        opcache_compile_file($file->getPathname());
    }
}
?>

JITの登場

オペコードがキャッシュされていても、VMはそれを解釈し続けます。JITはホットなオペコードの連続をネイティブCPU命令にコンパイルし、VMディスパッチのオーバーヘッドを取り除きます。CPU負荷の高い数値計算コードでは大きな効果がありますが、一般的なI/OバウンドのWebアプリでは、CPUではなくDBやネットワークに時間を使うため、効果は控えめです。

JITの設定

JITはOPcache内部で動作するため、OPcacheを有効にする必要があります。opcache.jit_buffer_sizeは生成されたマシンコード用の領域を確保します(0にするとJITは無効になります)。opcache.jitは、起動条件と最適化戦略を制御する4桁のモードです。

; Enable JIT (requires opcache.enable=1)
opcache.jit_buffer_size = 128M
opcache.jit = tracing        ; alias for 1254, the common default

; The 4 digits CRTO mean:
;   C - CPU optimization flags
;   R - register allocation
;   T - trigger (when to JIT)
;   O - optimization level

トレーシングJITと関数JIT

戦略は2つあります。関数JIT(モード1205)は、最初の呼び出し時に関数全体をコンパイルします。トレーシングJIT(1254、デフォルトのtracingエイリアス)は、実行をプロファイリングしてホットなループやパスをコンパイルします。観測された型に特化するため、より良い結果になることが多く、推奨されるデフォルト設定です。

; Tracing JIT (recommended) — compiles hot traces
opcache.jit = tracing

; Function JIT — compiles entire functions when first called
; opcache.jit = function

; Disable JIT but keep opcode cache
; opcache.jit_buffer_size = 0

JITの効果を測定する

JITは、タイトな数値計算ループで威力を発揮します。この自己完結型ベンチマーク(マンデルブロ集合風の内部ループ)は、JITによって実行時間を大幅に短縮できるCPU負荷の高い処理の一例です。jit_buffer_sizeを設定した場合と設定しない場合で実行して比較してください。

<?php
function mandelEscape(float $cr, float $ci, int $max): int {
    $zr = 0.0; $zi = 0.0; $n = 0;
    while ($n < $max && ($zr * $zr + $zi * $zi) <= 4.0) {
        $t  = $zr * $zr - $zi * $zi + $cr;
        $zi = 2.0 * $zr * $zi + $ci;
        $zr = $t;
        $n++;
    }
    return $n;
}

$start = hrtime(true);
$sum = 0;
for ($y = 0; $y < 200; $y++) {
    for ($x = 0; $x < 200; $x++) {
        $sum += mandelEscape($x / 100 - 2, $y / 100 - 1, 256);
    }
}
printf("sum=%d  time=%.2f ms\n", $sum, (hrtime(true) - $start) / 1e6);
?>

効果を期待できない場合

一般的なリクエストでは、DBにクエリを発行し、テンプレートをレンダリングしてJSONを返すため、CPUは生の算術演算をほとんど行いません。JITの効果は1桁パーセント程度、またはまったくない場合があります。まずはOPcache、プリロード、適切なDB/キャッシュの利用を優先してください。JITのチューニングは、画像処理、数学計算、パーサーなど、計算負荷の高いコードに限定してください。

確認問題

通常のOPcacheキャッシュにはない、プリロードの利点は何ですか?

まとめ

OPcacheはコンパイル済みop_arraysを共有メモリにキャッシュし、オプティマイザも実行します。本番環境ではvalidate_timestamps=0を設定し、memory_consumption/max_accelerated_filesを適切なサイズにしてください。プリロードは、選択したクラスを起動時から常駐させます。JIT(OPcache内部で動作し、jit_buffer_sizeが必要)はホットなコードをネイティブ命令にコンパイルします。CPU負荷の高い数学処理では大きな効果がありますが、I/OバウンドのWebアプリでは効果は小さいです。opcache_get_status()で確認してください。

よくある質問

「OPcacheとJITコンパイル」レッスンは無料ですか?

はい。「OPcacheとJITコンパイル」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、PHP Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 PHP Academyコースには全4レッスンが含まれています。

「OPcacheとJITコンパイル」で何を学びますか?

バイトコードキャッシュとJITでPHPを高速化します。 ブラウザで直接実行するハンズオンコードでPHP Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

PHP Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのPHP Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「OPcacheとJITコンパイル」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このPHP Academyレッスンでコードを書いて実行できますか?

はい。すべてのPHP Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Zend Engineの仕組み
  2. メモリ管理とガベージコレクション
  3. OPcacheとJITコンパイル
  4. Cで基本的なPHP拡張機能を書く
← PHP Academyに戻る