PHP 8 Performance Tuning: OpCache and JIT Explained
Your PHP 8 application feels sluggish under load. You've optimized queries, added caching, but response times still lag. The culprit might be PHP's own execution overhead. Two powerful features—OpCache and JIT—can dramatically speed up your code, but only if configured correctly. This guide explains how they work and how to tune them for real-world workloads.
What is OpCache and Why It Matters
PHP is an interpreted language: each request normally parses and compiles your source files into bytecode before executing. OpCache stores that compiled bytecode in shared memory, so subsequent requests skip parsing and compilation. The result? Lower CPU usage and faster response times.
OpCache is enabled by default in many production setups, but default settings are conservative. Tuning it can yield 2–3x throughput improvements for CPU-bound applications.
Key OpCache Configuration Directives
- opcache.enable: Set to 1 to enable. (Default: 1 in production, 0 in CLI unless overridden.)
- opcache.memory_consumption: Shared memory size in MB. Start with 128 MB; increase if you see high
opcache.memory_usage. - opcache.max_accelerated_files: Maximum number of files cached. Set to a prime number larger than your total PHP files (e.g., 10007).
- opcache.validate_timestamps: When 1, PHP checks file timestamps for changes. Set to 0 in production to avoid stat calls; you must manually clear cache after deployments.
- opcache.revalidate_freq: How often (in seconds) to check timestamps if validate_timestamps=1. Set to 0 for development, 60+ for production.
- opcache.interned_strings_buffer: Memory for interned strings (MB). Increase to 16 or 32 for large apps.
- opcache.fast_shutdown: Deprecated in PHP 7.2+, removed in PHP 8.0. Ignore.
- opcache.preload: Path to a preload script (PHP 7.4+). Preloading compiles and caches files at startup, eliminating per-request overhead for critical classes.
Recommended OpCache Settings for Production
; php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.interned_strings_buffer=32
opcache.preload=/path/to/preload.php
opcache.preload_user=www-data
After changing settings, restart PHP-FPM. Monitor with opcache_get_status() to check hit rate and memory usage.
Understanding JIT in PHP 8
JIT (Just-In-Time) compilation takes OpCache a step further: it compiles bytecode into native machine code at runtime. This can significantly speed up CPU-intensive tasks like mathematical computations, but it does little for typical web requests dominated by I/O (database, filesystem, network).
JIT is part of OpCache, so you must enable OpCache first. In PHP 8, JIT is configured via opcache.jit and opcache.jit_buffer_size.
JIT Configuration Directives
- opcache.jit: Controls JIT mode. Use
tracing(default) orfunction. The value is a 4-digit CRTO code:CRTOwhere C=CPU-specific optimization, R=register allocation, T=trigger, O=optimization level. For most apps,opcache.jit=tracingis fine. - opcache.jit_buffer_size: Memory for JIT code in bytes. Start with 64M or 128M. If set to 0, JIT is disabled.
- opcache.jit_hot_loop, opcache.jit_hot_func, opcache.jit_hot_return, opcache.jit_hot_side_exit: Thresholds for hot code detection. Defaults are usually okay.
Recommended JIT Settings
opcache.jit=tracing
opcache.jit_buffer_size=128M
Note: JIT only works with OpCache enabled. In CLI, you may need to set opcache.enable_cli=1 to test JIT.
OpCache vs JIT: When to Use Which
| Feature | OpCache | JIT |
|---|---|---|
| Primary benefit | Caches compiled bytecode | Compiles bytecode to native code |
| Best for | All PHP applications | CPU-intensive, long-running scripts |
| Impact on I/O-bound apps | High (reduces parsing/compilation) | Low to none |
| Memory overhead | Moderate | Additional buffer |
| Complexity | Low | Medium |
Step-by-Step Tuning Guide
- Enable OpCache with the recommended settings above.
- Monitor OpCache using
opcache_get_status()or tools like OpCache GUI. Aim for a hit rate above 99%. - Adjust memory if
opcache.memory_usageis near the limit. - Consider preloading for large frameworks (Laravel, Symfony). Create a preload script that requires frequently used classes.
- Enable JIT only if your app is CPU-bound. Test with and without JIT to measure impact.
- Benchmark using tools like
ab,wrk, orsiege. Compare requests per second and latency. - Deploy changes gradually and monitor error logs for issues.
Common Pitfalls and Best Practices
- Don't disable validate_timestamps in development: You'll waste time wondering why code changes don't take effect.
- Clear OpCache on deploy: If validate_timestamps=0, you must reset OpCache (e.g., by restarting PHP-FPM or calling
opcache_reset()). - JIT is not a silver bullet: For typical CRUD apps, OpCache alone provides most gains.
- Watch memory: JIT buffer and OpCache memory add to PHP's footprint. Ensure your server has enough RAM.
- Use preloading carefully: Preloaded files are always in memory; avoid preloading everything.
FAQ
Does JIT improve performance for all PHP applications?
No. JIT benefits CPU-intensive tasks like complex calculations or data processing. For I/O-bound web apps (database queries, API calls), the gains are minimal. OpCache alone often provides the biggest speedup.
How do I know if OpCache is working?
Check phpinfo() for OpCache status, or call opcache_get_status() in a script. Look for opcache_enabled => true and a high hits count relative to misses.
Can I use JIT with PHP 7?
No. JIT was introduced in PHP 8.0. PHP 7 only supports OpCache. If you're on PHP 7, focus on OpCache tuning and consider upgrading to PHP 8 for JIT and other performance improvements.
Ready to analyze your server's performance? Check out our Nginx Log Analyzer to gain insights from your access logs and identify bottlenecks.