Skip to main content

PHP OPcache: Setup and Byte-Code Cache Optimization

PHP · 19.04.2026 · 4 min read
Illustration for “PHP OPcache: Setup and Byte-Code Cache Optimization”

What Is PHP OPcache

PHP OPcache speeds up PHP script execution by keeping compiled byte-code in shared memory. On repeat requests PHP skips the parsing and compilation stages, which yields a speed gain of 2 to 10 times. OPcache is enabled in PHP 5.5+ and ships with PHP itself — no separate installation is required.

Checking OPcache Status

php -r "echo opcache_get_status() ? 'Enabled' : 'Disabled';"

Or create the file /var/www/html/opcache-info.php:

<?php
$status = opcache_get_status();
echo "Memory used: " . round($status['memory_usage']['used_memory']/1024/1024) . " MB\n";
echo "Hit rate: " . round($status['opcache_statistics']['opcache_hit_rate'], 2) . "%\n";

Enabling and Configuring OPcache

Open the file /etc/php/8.2/fpm/php.ini or create /etc/php/8.2/mods-available/opcache.ini:

opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
opcache.validate_timestamps=1
opcache.save_comments=1
opcache.fast_shutdown=1

Key Parameters Explained

ParameterValueDescription
memory_consumption128–512 MBRAM for the byte-code cache
max_accelerated_files4000–100000Maximum number of cached files
revalidate_freq0 (prod) / 2 (dev)How often file changes are checked (sec)
validate_timestamps0 (prod) / 1 (dev)Whether to check file modification time
For production: set validate_timestamps=0 and revalidate_freq=0 — that is maximum speed. After deploying code, flush the cache with php -r "opcache_reset();" or by reloading PHP-FPM.

Optimal Settings for WordPress / Laravel

opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.revalidate_freq=0
opcache.validate_timestamps=0
opcache.interned_strings_buffer=16
opcache.jit=1255
opcache.jit_buffer_size=128M

JIT Compilation in PHP 8.x

PHP 8.0+ supports JIT (Just-In-Time) compilation on top of OPcache. For CPU-intensive workloads (image processing, cryptography, scientific computing) JIT delivers an extra speed-up:

opcache.jit=1255
opcache.jit_buffer_size=128M
JIT does not meaningfully speed up ordinary web applications (WordPress, Laravel) — they are limited by I/O, not by CPU. Enable JIT only if your applications really are CPU-bound.

Resetting the OPcache

# Via PHP CLI
php -r "opcache_reset();"

# Reload PHP-FPM
sudo systemctl reload php8.2-fpm

# Via wp-cli (for WordPress)
wp cache flush

Real OPcache Errors

Not enough shared memory

PHP Warning:  PHP Startup: Unable to allocate shared memory segment of 268435456 bytes in Unknown on line 0

Most often seen inside Docker containers: by default /dev/shm is capped at 64 MB, while opcache.memory_consumption asks for 256 MB. The fix is either to increase the container's --shm-size, or to lower the cache's memory allocation to what is actually available.

The cache silently fills up

The trickiest OPcache situation comes with no error text at all. When the number of project files exceeds opcache.max_accelerated_files, new files simply stop being cached: the site does not crash, it just quietly gets slower. The only way to spot this is by checking the status:

php -r "var_dump(opcache_get_status()['cache_full']);"
// bool(true) — the cache is full, new scripts get recompiled on every request

When OPcache Is Nearly Useless

  • Short-lived CLI scripts (one-off handlers, single-line cron jobs) — every run is a fresh process with no shared memory with the previous one, so there is nothing to cache. That is why opcache.enable_cli=0 is the default.
  • Long-running queue workers are the exception to that rule: if a process lives for hours and reuses the same code, turning on opcache.enable_cli=1 for it is worthwhile.
  • Active development with validate_timestamps=0 — file changes stop being picked up entirely, not just with a delay, which looks like "my edit did not apply" and causes confusion until someone remembers this setting.

Verifying the Result

Status fieldHealthy value
opcache_hit_rateAbove 95%
cache_fullfalse
num_cached_scriptsClose to the total number of PHP files in the project
php -r '
$s = opcache_get_status();
echo "hit_rate: " . round($s["opcache_statistics"]["opcache_hit_rate"], 1) . "%
";
echo "cache_full: " . var_export($s["cache_full"], true) . "
";
echo "cached: " . $s["opcache_statistics"]["num_cached_scripts"] . "
";
'

If cache_full is true, raise opcache.max_accelerated_files with headroom: count the actual number of PHP files in the project with find . -name "*.php" | wc -l and use a value at least twice that. For fine-tuning JIT on top of OPcache, see the dedicated article.

Keep at least a 1.5–2x margin: the number of project files growing after a framework update or a new library pulled in through Composer is routine, and without headroom the cache will fill up again within a couple of releases.

Was this article helpful?
← Back to Knowledge Base Ask Support