OPcache Configuration for PHP

Introduction

OPcache is a powerful opcode caching engine built into PHP since version 5.5. It dramatically improves PHP performance by storing precompiled script bytecode in shared memory, eliminating the need to parse and compile PHP scripts on every request. This optimization can reduce response times by 30-70% and increase throughput by 2-5x, making it one of the most impactful performance improvements available for PHP applications.

Without OPcache, PHP must read, parse, and compile scripts on every single request, consuming significant CPU resources and adding latency. With OPcache enabled and properly configured, this compilation happens once, and the optimized bytecode is reused across thousands or millions of requests. For high-traffic websites, this translates to massive performance gains and reduced server load.

This comprehensive guide covers OPcache architecture, configuration options, optimization techniques, monitoring, and troubleshooting. You'll learn how to properly configure OPcache to maximize performance while avoiding common pitfalls that can cause stale code, memory exhaustion, or security issues.

Understanding OPcache

How OPcache Works

  1. First Request: PHP parses and compiles script to opcode
  2. Storage: Compiled opcode stored in shared memory
  3. Subsequent Requests: Opcode retrieved directly from memory
  4. Optimization: OPcache applies additional optimizations to opcode

Performance Impact

Without OPcache:

Request → Parse PHP → Compile to Opcode → Execute → Response
Time: 50ms parsing + 100ms execution = 150ms total

With OPcache:

Request → Retrieve Opcode from Memory → Execute → Response
Time: 0.5ms retrieval + 100ms execution = 100.5ms total
33% faster response time

OPcache Components

  • Opcode Cache: Stores compiled bytecode
  • Interned Strings Buffer: Stores immutable strings (reduces memory)
  • File Cache: Optional persistent file-based cache
  • Optimization Passes: Code optimization algorithms

Installation and Verification

Check OPcache Status

# Check if OPcache is installed
php -m | grep -i opcache

# View OPcache configuration
php --ri opcache

# Check via PHP script
php -r "var_dump(opcache_get_status());"

# View OPcache settings
php -i | grep -i opcache

Enable OPcache

# Ubuntu/Debian
apt-get install php8.3-opcache -y

# CentOS/Rocky Linux
dnf install php-opcache -y

# Verify extension is loaded
php -m | grep OPcache

# Configuration file location
# Ubuntu/Debian: /etc/php/8.3/mods-available/opcache.ini
# CentOS/Rocky: /etc/php.d/10-opcache.ini

Benchmarking Before Optimization

Baseline Performance Test

# Create test script
cat > /var/www/html/opcache-test.php << 'EOF'
<?php
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
    $data = [
        'id' => $i,
        'name' => 'User ' . $i,
        'email' => 'user' . $i . '@example.com'
    ];
    json_encode($data);
}
echo "Execution time: " . (microtime(true) - $start) . " seconds\n";
EOF

# Test without OPcache
php -d opcache.enable=0 /var/www/html/opcache-test.php
# Result: 0.045 seconds

# Test with OPcache
php -d opcache.enable=1 /var/www/html/opcache-test.php
# Result: 0.012 seconds (73% faster)

Web Server Load Test

# Install Apache Bench
apt-get install apache2-utils -y

# Test with OPcache disabled
ab -n 1000 -c 100 http://localhost/index.php

# Baseline results (OPcache disabled):
# Requests per second: 450
# Time per request: 222ms (mean)
# Memory usage: High
# CPU usage: 85%

# Test with OPcache enabled
ab -n 1000 -c 100 http://localhost/index.php

# Optimized results (OPcache enabled):
# Requests per second: 1,850 (311% improvement)
# Time per request: 54ms (76% faster)
# Memory usage: Lower
# CPU usage: 42% (50% reduction)

Essential OPcache Configuration

Basic Configuration

; /etc/php/8.3/mods-available/opcache.ini

[opcache]
; Enable OPcache
opcache.enable=1
opcache.enable_cli=0

; Memory configuration
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000

; Performance settings
opcache.revalidate_freq=60
opcache.fast_shutdown=1

; Advanced features
opcache.save_comments=1
opcache.enable_file_override=0

Memory Configuration

; OPcache memory allocation (MB)
; Default: 128MB
; Recommended: 128-512MB depending on application size
opcache.memory_consumption=256

; Interned strings buffer (MB)
; Stores immutable strings, reduces memory duplication
; Default: 8MB
; Recommended: 16-32MB for large applications
opcache.interned_strings_buffer=16

; Maximum number of files in cache
; Default: 10000
; Calculate: count all .php files in your application
; Add 20-30% buffer
opcache.max_accelerated_files=20000

Calculate max_accelerated_files:

# Count PHP files in application
find /var/www/html -type f -name "*.php" | wc -l
# Output: 14,523

# Add 30% buffer: 14,523 × 1.3 = 18,879
# Round to nearest prime: 20,000 (nearest available)
opcache.max_accelerated_files=20000

# Available values: 200, 1000, 2000, 4000, 8000, 16000, 32768

Validation and Revalidation

; Revalidation frequency (seconds)
; How often OPcache checks if files have changed
; Default: 2
; Production: 60-3600 (higher = better performance)
; Development: 0 (always check)
opcache.revalidate_freq=60

; Validate timestamps
; Enable file change checking
; Production: 1 (enabled)
; High-traffic production: 0 (disabled, use manual cache reset)
opcache.validate_timestamps=1

; Maximum file size to cache (bytes)
; Default: 0 (unlimited)
; Set if you have extremely large PHP files
opcache.max_file_size=0

Optimized Configurations by Environment

Development Environment

; /etc/php/8.3/mods-available/opcache.ini

[opcache]
; Enable OPcache
opcache.enable=1
opcache.enable_cli=0

; Memory (smaller allocation)
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000

; Validate every request (detect code changes immediately)
opcache.revalidate_freq=0
opcache.validate_timestamps=1

; Optimization level
opcache.optimization_level=0x7FFFBFFF

; Error handling
opcache.log_verbosity_level=4
error_log=/var/log/php-opcache-errors.log

; Debugging
opcache.consistency_checks=1

Production Environment (Medium Traffic)

[opcache]
; Enable OPcache
opcache.enable=1
opcache.enable_cli=0

; Memory allocation
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000

; Revalidation (check every minute)
opcache.revalidate_freq=60
opcache.validate_timestamps=1

; Performance
opcache.fast_shutdown=1
opcache.enable_file_override=0

; Optimization
opcache.optimization_level=0x7FFFBFFF
opcache.save_comments=1

; Monitoring
opcache.log_verbosity_level=1

; File cache (optional, for faster restarts)
opcache.file_cache=/tmp/opcache
opcache.file_cache_consistency_checks=1

Production Environment (High Traffic)

[opcache]
; Enable OPcache
opcache.enable=1
opcache.enable_cli=0

; Large memory allocation
opcache.memory_consumption=512
opcache.interned_strings_buffer=32
opcache.max_accelerated_files=32768

; Maximum performance (disable timestamp validation)
opcache.revalidate_freq=0
opcache.validate_timestamps=0

; Performance optimizations
opcache.fast_shutdown=1
opcache.enable_file_override=0
opcache.huge_code_pages=1

; Maximum optimization
opcache.optimization_level=0x7FFFBFFF
opcache.save_comments=1

; File cache for faster restarts
opcache.file_cache=/var/cache/opcache
opcache.file_cache_only=0

; Minimal logging
opcache.log_verbosity_level=1

Performance Results:

Medium Traffic Config:
- Requests/sec: 1,850
- Response time: 54ms
- CPU: 42%

High Traffic Config (timestamps disabled):
- Requests/sec: 2,470 (33% more)
- Response time: 40ms (26% faster)
- CPU: 31% (26% less)

Advanced Configuration Options

Optimization Level

; Optimization level (bitmask)
; Default: 0x7FFFBFFF (all optimizations)
opcache.optimization_level=0x7FFFBFFF

; Disable specific optimizations (if causing issues):
; 0x7FFFFFFF = all optimizations except pass 9
; 0x7FFFFEFF = disable pass 8
; Typically, use default unless debugging specific issues

JIT Configuration (PHP 8.0+)

; JIT (Just-In-Time compilation) - PHP 8.0+
; Enabled by default in PHP 8, provides additional performance

; JIT buffer size (MB)
opcache.jit_buffer_size=128

; JIT mode
; 1255 = tracing JIT (recommended for most applications)
; 1205 = function JIT
; 0 = disabled
opcache.jit=1255

; JIT debug level
opcache.jit_debug=0

JIT Performance Impact:

# Test CPU-intensive task
ab -n 1000 -c 100 http://localhost/compute.php

# Without JIT:
# Requests/sec: 1,450
# Time per request: 69ms

# With JIT (1255):
# Requests/sec: 3,280 (126% improvement)
# Time per request: 30ms (56% faster)

File Cache Configuration

; Persistent file cache (survive PHP-FPM restarts)
; Path to file cache directory
opcache.file_cache=/var/cache/opcache

; Use file cache as fallback
opcache.file_cache_fallback=1

; Consistency checks
opcache.file_cache_consistency_checks=1

; Only use file cache (no shared memory)
; Useful for restrictive environments
opcache.file_cache_only=0
# Create and configure file cache directory
mkdir -p /var/cache/opcache
chown www-data:www-data /var/cache/opcache
chmod 755 /var/cache/opcache

Huge Pages Support

; Enable huge pages for better performance
; Requires system configuration
opcache.huge_code_pages=1
# Enable huge pages on system
echo "vm.nr_hugepages=128" >> /etc/sysctl.conf
sysctl -p

# Verify huge pages
cat /proc/meminfo | grep Huge

# Expected output:
# HugePages_Total:     128
# HugePages_Free:      120
# Hugepagesize:       2048 kB

Cache Management

Manual Cache Reset

# Reset OPcache via PHP script
cat > /var/www/html/opcache-reset.php << 'EOF'
<?php
if (function_exists('opcache_reset')) {
    opcache_reset();
    echo "OPcache reset successfully\n";
} else {
    echo "OPcache not available\n";
}
EOF

# Secure the reset script (restrict access)
# Or use from command line:
php -r "opcache_reset();"

# Reset via PHP-FPM reload (graceful)
systemctl reload php8.3-fpm

Deployment Strategy

#!/bin/bash
# deployment script with OPcache management

# Deploy new code
git pull origin main

# Option 1: Clear OPcache (for validate_timestamps=0)
php -r "opcache_reset();"

# Option 2: Reload PHP-FPM (graceful, no downtime)
systemctl reload php8.3-fpm

# Option 3: Restart PHP-FPM (complete restart)
# systemctl restart php8.3-fpm

# Verify deployment
curl http://localhost/health-check.php

Preloading (PHP 7.4+)

; Preload frequently used files
; Loaded once at PHP-FPM startup
opcache.preload=/var/www/html/preload.php
opcache.preload_user=www-data
<?php
// /var/www/html/preload.php
// Preload framework and frequently used files

opcache_compile_file('/var/www/html/vendor/autoload.php');
opcache_compile_file('/var/www/html/app/Kernel.php');
opcache_compile_file('/var/www/html/app/Http/Controllers/Controller.php');

// Preload all controllers
$files = glob('/var/www/html/app/Http/Controllers/*.php');
foreach ($files as $file) {
    opcache_compile_file($file);
}

Monitoring OPcache

Enable OPcache Status Page

<?php
// /var/www/html/opcache-status.php
// Restrict access in production!

if (!in_array($_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1'])) {
    die('Access denied');
}

$status = opcache_get_status();
$config = opcache_get_configuration();

echo "<h1>OPcache Status</h1>";

// Memory usage
echo "<h2>Memory Usage</h2>";
echo "Used: " . round($status['memory_usage']['used_memory'] / 1024 / 1024, 2) . " MB<br>";
echo "Free: " . round($status['memory_usage']['free_memory'] / 1024 / 1024, 2) . " MB<br>";
echo "Wasted: " . round($status['memory_usage']['wasted_memory'] / 1024 / 1024, 2) . " MB<br>";
echo "Wasted %: " . round($status['memory_usage']['current_wasted_percentage'], 2) . "%<br>";

// Hit rate
$hits = $status['opcache_statistics']['hits'];
$misses = $status['opcache_statistics']['misses'];
$total = $hits + $misses;
$hit_rate = ($total > 0) ? ($hits / $total * 100) : 0;

echo "<h2>Hit Rate</h2>";
echo "Hits: " . number_format($hits) . "<br>";
echo "Misses: " . number_format($misses) . "<br>";
echo "Hit Rate: " . round($hit_rate, 2) . "%<br>";

// Cache state
echo "<h2>Cache State</h2>";
echo "Cached scripts: " . $status['opcache_statistics']['num_cached_scripts'] . "<br>";
echo "Cached keys: " . $status['opcache_statistics']['num_cached_keys'] . "<br>";
echo "Max cached keys: " . $status['opcache_statistics']['max_cached_keys'] . "<br>";

// Interned strings
echo "<h2>Interned Strings</h2>";
echo "Buffer size: " . round($status['interned_strings_usage']['buffer_size'] / 1024 / 1024, 2) . " MB<br>";
echo "Used: " . round($status['interned_strings_usage']['used_memory'] / 1024 / 1024, 2) . " MB<br>";
echo "Free: " . round($status['interned_strings_usage']['free_memory'] / 1024 / 1024, 2) . " MB<br>";
echo "Strings: " . number_format($status['interned_strings_usage']['number_of_strings']) . "<br>";
?>

Monitoring Script

#!/bin/bash
# /usr/local/bin/opcache-monitor.sh

STATUS=$(php -r "var_export(opcache_get_status());")

# Parse key metrics
MEMORY_USED=$(echo "$STATUS" | grep -A1 "'used_memory'" | tail -n1 | grep -oP '\d+')
MEMORY_FREE=$(echo "$STATUS" | grep -A1 "'free_memory'" | tail -n1 | grep -oP '\d+')
MEMORY_WASTED=$(echo "$STATUS" | grep -A1 "'wasted_memory'" | tail -n1 | grep -oP '\d+')
HITS=$(echo "$STATUS" | grep -A1 "'hits'" | tail -n1 | grep -oP '\d+')
MISSES=$(echo "$STATUS" | grep -A1 "'misses'" | tail -n1 | grep -oP '\d+')

# Calculate metrics
TOTAL=$((HITS + MISSES))
if [ $TOTAL -gt 0 ]; then
    HIT_RATE=$(awk "BEGIN {printf \"%.2f\", ($HITS/$TOTAL)*100}")
else
    HIT_RATE="0"
fi

MEMORY_USED_MB=$(awk "BEGIN {printf \"%.2f\", $MEMORY_USED/1024/1024}")
WASTED_PCT=$(awk "BEGIN {printf \"%.2f\", ($MEMORY_WASTED/($MEMORY_USED+$MEMORY_FREE+$MEMORY_WASTED))*100}")

# Log metrics
echo "$(date) - Memory: ${MEMORY_USED_MB}MB, Wasted: ${WASTED_PCT}%, Hit Rate: ${HIT_RATE}%" >> /var/log/opcache-monitor.log

# Alert if issues
if (( $(echo "$WASTED_PCT > 10" | bc -l) )); then
    echo "WARNING: OPcache wasted memory at ${WASTED_PCT}%" | mail -s "OPcache Alert" [email protected]
fi

if (( $(echo "$HIT_RATE < 95" | bc -l) )); then
    echo "WARNING: OPcache hit rate at ${HIT_RATE}%" | mail -s "OPcache Alert" [email protected]
fi

Key Metrics to Monitor

  1. Hit Rate: Should be > 99% in production
  2. Memory Usage: Should not exceed 80% of allocated
  3. Wasted Memory: Should be < 5%
  4. Cached Scripts: Monitor for unexpected changes
  5. Cache Full Events: Should be 0

Troubleshooting

Issue 1: Low Hit Rate

Diagnosis:

# Check hit rate
php -r "var_dump(opcache_get_status()['opcache_statistics']);"

# Low hit rate causes:
# 1. OPcache too small
# 2. Cache being cleared frequently
# 3. revalidate_freq too low

Solutions:

; Increase memory
opcache.memory_consumption=512
opcache.max_accelerated_files=32768

; Increase revalidation frequency
opcache.revalidate_freq=300

; Disable timestamp validation in production
opcache.validate_timestamps=0

Issue 2: High Memory Waste

Diagnosis:

# Check wasted memory percentage
php -r "var_dump(opcache_get_status()['memory_usage']);"

# Wasted memory > 5% indicates fragmentation

Solutions:

# Reset OPcache to defragment
php -r "opcache_reset();"

# Or restart PHP-FPM
systemctl restart php8.3-fpm

# Schedule regular restarts during low-traffic periods
# 0 4 * * * systemctl restart php8.3-fpm

Issue 3: Stale Code After Deployment

Symptoms: Old code running after deployment

Solutions:

# Option 1: Reset OPcache manually
php -r "opcache_reset();"

# Option 2: Reload PHP-FPM
systemctl reload php8.3-fpm

# Option 3: Enable timestamp validation
# In php.ini:
opcache.validate_timestamps=1
opcache.revalidate_freq=2

# Option 4: Use deployment script
#!/bin/bash
git pull
php -r "opcache_reset();"
systemctl reload php8.3-fpm

Issue 4: Out of Memory Errors

Diagnosis:

# Check if OPcache is full
php -r "
\$status = opcache_get_status();
\$used = \$status['memory_usage']['used_memory'];
\$total = \$used + \$status['memory_usage']['free_memory'];
echo 'Usage: ' . round(\$used/\$total*100, 2) . '%';
"

Solutions:

; Increase OPcache memory
opcache.memory_consumption=512

; Increase max files
opcache.max_accelerated_files=32768

; Increase interned strings buffer
opcache.interned_strings_buffer=32

Performance Comparison

Real-World Application Tests

WordPress Site:

# Without OPcache
ab -n 1000 -c 100 http://localhost/
# Requests/sec: 42
# Time per request: 2,381ms
# CPU: 92%

# With OPcache (optimized)
ab -n 1000 -c 100 http://localhost/
# Requests/sec: 187 (345% improvement)
# Time per request: 535ms (77% faster)
# CPU: 45% (51% reduction)

Laravel Application:

# Without OPcache
ab -n 5000 -c 500 http://localhost/api/users
# Requests/sec: 285
# Time per request: 1,754ms

# With OPcache + JIT
ab -n 5000 -c 500 http://localhost/api/users
# Requests/sec: 1,340 (370% improvement)
# Time per request: 373ms (79% faster)

Best Practices

Configuration Guidelines

  1. Memory Allocation

    • Development: 128-256 MB
    • Production (small): 256-512 MB
    • Production (large): 512-1024 MB
  2. File Limits

    • Count your PHP files
    • Add 30% buffer
    • Use nearest prime/power of 2
  3. Revalidation

    • Development: 0 (always check)
    • Production (moderate): 60-300 seconds
    • Production (high-traffic): disable validation
  4. Monitoring

    • Check hit rate daily
    • Monitor memory usage
    • Track wasted memory
    • Alert on anomalies
  5. Deployment

    • Always reset cache after code changes
    • Use graceful PHP-FPM reload
    • Test in staging first
    • Monitor after deployment

Conclusion

OPcache is one of the most effective PHP performance optimizations available. Proper configuration delivers substantial benefits:

Performance Improvements:

  • Response times: 30-70% faster
  • Throughput: 2-5x increase
  • CPU usage: 40-60% reduction
  • Server capacity: 3-10x more requests per server

Key Success Factors:

  1. Enable OPcache on all production servers
  2. Allocate sufficient memory based on application size
  3. Optimize for your environment (dev vs production)
  4. Monitor continuously to detect issues
  5. Manage cache properly during deployments

Essential Settings Summary:

; Production (high-traffic)
opcache.enable=1
opcache.memory_consumption=512
opcache.max_accelerated_files=32768
opcache.revalidate_freq=0
opcache.validate_timestamps=0
opcache.interned_strings_buffer=32
opcache.fast_shutdown=1
opcache.jit_buffer_size=128
opcache.jit=1255

By implementing these OPcache optimizations, you can dramatically improve PHP application performance, reduce infrastructure costs, and provide better user experience with minimal configuration changes.