0Pricing
PHP Academy · Lesson

OPcache and JIT Compilation

Speed up PHP with bytecode caching and JIT.

OPcache and JIT Compilation is a free PHP Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the PHP Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Caching the Compile

OPcache stores compiled opcodes in shared memory so PHP skips lexing, parsing, and compiling on every request. On top of that, JIT (since PHP 8.0) compiles hot opcodes to native machine code. Together they're the backbone of PHP performance.

This lesson covers configuring OPcache, preloading, and tuning JIT.

What OPcache Does

The compiled op_array for each file is cached in a shared-memory segment used by all FPM workers. A request that hits the cache reuses opcodes directly. OPcache also runs an optimizer (constant folding, dead-code elimination, opcode fusion) the first time it compiles a file.

; 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

Timestamp Validation

validate_timestamps decides whether OPcache re-checks file mtimes. In development keep it on with a short revalidate_freq; in production set it to 0 so PHP never stats files, and deploy by clearing the cache (or rebuilding the image).

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

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

Inspecting the Cache

opcache_get_status() reports hit rate, memory usage, and cached scripts; opcache_get_configuration() shows settings. A low hit ratio or frequent restarts means too little memory or too many files.

<?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";
}
?>

Preloading

Preloading (PHP 7.4+) compiles a set of classes/functions once at server startup and keeps them permanently in memory, available to every request with no autoload or per-request linking. Point opcache.preload at a script that requires the files to warm.

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

Writing a Preload Script

The preload script runs in the master process. Use opcache_compile_file() to load classes without executing them, or simply require them. Frameworks generate a preload list; here's the shape of one.

<?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());
    }
}
?>

Enter the JIT

Even with cached opcodes, the VM still interprets them. JIT compiles hot opcode sequences to native CPU instructions, removing VM dispatch overhead. The gain is large for CPU-bound numeric code, modest for typical I/O-bound web apps (which spend time in DB/network, not the CPU).

Configuring JIT

JIT lives inside OPcache, so OPcache must be on. opcache.jit_buffer_size allocates space for generated machine code (0 disables JIT). opcache.jit is a 4-digit mode controlling trigger and optimization strategy.

; 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

Tracing vs Function JIT

Two strategies: function JIT (mode 1205) compiles whole functions on first call; tracing JIT (1254, the default tracing alias) profiles execution and compiles hot loops/paths, often yielding better results because it specializes on observed types. Tracing is the recommended default.

; 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

Measuring JIT Impact

JIT shines on tight numeric loops. This self-contained benchmark (a Mandelbrot-ish inner loop) is the kind of CPU-bound workload where JIT can cut runtime substantially; run it with and without jit_buffer_size to compare.

<?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);
?>

When NOT to Expect Gains

For a typical request that queries a DB, renders a template, and returns JSON, the CPU does little raw arithmetic — JIT may give single-digit-percent gains or none. Prioritize OPcache + preloading + good DB/cache usage first. Reserve JIT tuning for image processing, math, parsers, and other compute-heavy code.

Quick Check

What does preloading give you that ordinary OPcache caching does not?

Recap

OPcache caches compiled op_arrays in shared memory and runs an optimizer; set validate_timestamps=0 in prod and size memory_consumption/max_accelerated_files properly. Preloading keeps chosen classes resident at startup. JIT (inside OPcache, needs jit_buffer_size) compiles hot code to native instructions — big wins for CPU-bound math, little for I/O-bound web apps. Use opcache_get_status() to verify.

Frequently asked questions

Is the “OPcache and JIT Compilation” lesson free?

Yes — the full text of “OPcache and JIT Compilation” is free to read here on the web, and the PHP Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the PHP Academy course, upgrade to CoddyKit PRO.

What will I learn in “OPcache and JIT Compilation”?

Speed up PHP with bytecode caching and JIT. You practise PHP Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start PHP Academy?

No prior experience is required. PHP Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “OPcache and JIT Compilation” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this PHP Academy lesson?

Yes. Every PHP Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. How the Zend Engine Works
  2. Memory Management and Garbage Collection
  3. OPcache and JIT Compilation
  4. Writing a Basic PHP Extension in C
← Back to PHP Academy