In PHP, how do you size opcache.memory_consumption and opcache.max_accelerated_files, and how do you tell that OPcache is full?
answer
- one shared segment for the whole server
- 128 MB and 10000 by default
- file limit rounds up to a prime
- full cache: new scripts run uncached
- opcache_get_status(): cache_full, hash_restarts
basics
~20 sSet opcache.max_accelerated_files above the number of PHP files the app can load, vendor included, and opcache.memory_consumption (default 128 MB) with headroom over measured use. opcache_get_status() shows a full cache as cache_full, low free memory, or rising oom_restarts or hash_restarts.
solid answer
~40 sTwo limits cap the cache. `opcache.max_accelerated_files` (default `10000`) sizes the hash table of scripts; OPcache rounds it up to the next prime in a fixed list, so `10000` really means `16229`. I set it above the count of `.php` files the application can load, `vendor/` included. `opcache.memory_consumption` (default `128`, in MB) sizes the shared segment that holds the compiled code; `opcache.interned_strings_buffer` (default `8` MB) is carved out of it for shared strings. When either limit is hit, OPcache stops caching new scripts — they are compiled on every request — and schedules a restart only if wasted memory has reached `opcache.max_wasted_percentage` (default `5`). I watch `opcache_get_status()`: `cache_full`, `memory_usage.free_memory`, `num_cached_keys` against `max_cached_keys`, and the `oom_restarts` and `hash_restarts` counters. Rising counters or a falling hit rate mean the limits are too low.
code
ini · 5 lines; sized for ~20 000 PHP files including vendor/
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=30000 ; rounds up to 32531
opcache.max_wasted_percentage=5go deeper
Know the two main limits — memory and number of files — and that opcache_get_status() shows whether they are enough.
Explain the prime rounding of max_accelerated_files, what happens to new scripts when the cache is full, and when an automatic restart is scheduled.
Size both limits from measured file counts and warmed-up memory, and alert on cache_full, restart counters and hit rate from inside the FPM pool.
Set fleet-wide OPcache baselines that are revisited on dependency upgrades, so cache pressure never becomes an unnoticed latency tax.
## Two separate limits OPcache stores compiled scripts in one shared memory segment and finds them through a hash table keyed by path. Each has its own limit, and either can fill first. | Directive | Default | Limits | |---|---|---| | `opcache.memory_consumption` | `128` (MB) | total shared memory for compiled scripts | | `opcache.interned_strings_buffer` | `8` (MB) | the part of that memory used for shared strings | | `opcache.max_accelerated_files` | `10000` | number of script keys in the hash table | | `opcache.max_wasted_percentage` | `5` | wasted share that allows an automatic restart | All four are `PHP_INI_SYSTEM`: they are read when the server starts, and every PHP-FPM pool under one master shares the same segment. PHP 8.5 reports an attempt to change `memory_consumption` once the segment exists, such as a per-pool override, instead of silently ignoring it. ## Sizing max_accelerated_files The value is not used as written. OPcache picks the first number in a fixed set of primes — `223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793` — that is at least the configured value, within a minimum of `200` and a maximum of `1000000`. The default of `10000` therefore gives `16229` slots. To size it: 1. Count the PHP files the application can load, including `vendor/` and generated code: `find . -name '*.php' | wc -l`. 2. Add headroom, because one file can occupy more than one key (a script reached through different paths) and new releases add files. 3. Choose a value that lands on the next prime comfortably above the total. Applications with large dependency trees routinely exceed the default. ## Sizing memory_consumption Memory depends on how much code is compiled, not on traffic. Start from the default, let a production server warm up, then read `memory_usage` from `opcache_get_status()`: - `used_memory`: what cached scripts occupy. - `free_memory`: what is left. - `wasted_memory`: space held by outdated entries, for example scripts replaced after a file changed or was invalidated. Set the limit so that `free_memory` keeps a healthy margin after a full warm-up. If `interned_strings_usage.free_memory` approaches zero, raise `opcache.interned_strings_buffer` too; once it overflows, OPcache logs "Interned string buffer overflow" and stops sharing new strings. ## What happens when it is full When OPcache cannot store a new script — out of memory or out of hash slots — it marks the cache as full and **compiles that script for the current request without caching it**. Every request that needs it pays the compile cost again. A restart of the cache is scheduled only when wasted memory has reached `opcache.max_wasted_percentage`; otherwise the cache simply stays full. The symptoms, all visible in `opcache_get_status()`: - `cache_full` is `true`. - `opcache_statistics.num_cached_keys` is at `max_cached_keys`. - `opcache_statistics.oom_restarts` or `hash_restarts` keeps increasing: each is a full flush followed by a recompile burst. - `opcache_statistics.opcache_hit_rate` drops below the high-90s you see on a healthy server. ## A worked sizing example Suppose a service ships about 21 000 PHP files including `vendor/`, and a warmed-up server reports roughly 150 MB of `used_memory` with the default settings and a non-zero `hash_restarts` counter. 1. The default `max_accelerated_files=10000` gives 16 229 slots — fewer than the files the application can load, which explains the hash restarts. 2. Setting `max_accelerated_files=30000` rounds up to 32 531 slots, leaving room for growth and for files reached through more than one path. 3. With 150 MB used against the default 128 MB, the memory limit is also too low; setting `memory_consumption=256` leaves a comfortable margin. 4. After the change, restart PHP-FPM (these settings are read only at startup), let traffic warm the cache, and confirm that `cache_full` stays `false` and both restart counters stop moving. The numbers are illustrative; the method — count files, measure warmed usage, add headroom, verify — is what carries over. ## A monitoring habit Export those fields to your metrics system from a small script that runs inside the PHP-FPM pool — a CLI call sees a different cache. Alert on `cache_full`, on any growth of `oom_restarts` or `hash_restarts`, and on a sustained drop in hit rate. After each major dependency upgrade, recheck the file count against `max_cached_keys`.
- Why might a server with plenty of free OPcache memory still report cache_full?The hash table can fill before the memory does. If the application has more distinct script keys than the prime chosen from `opcache.max_accelerated_files`, new scripts cannot be indexed, so OPcache marks the cache full and compiles them uncached. `hash_restarts` and `num_cached_keys` at `max_cached_keys` reveal it.
- What does wasted memory mean in opcache_get_status()?Space still held by cached scripts that are no longer valid, such as a file that changed or was invalidated and was compiled again elsewhere in the segment. OPcache does not reclaim it piecemeal; it is freed when the cache restarts, which happens automatically only once the waste reaches `opcache.max_wasted_percentage`.
saying these in an interview costs you the question
- max_accelerated_files is used exactly as configured
- When OPcache is full it evicts the least recently used scripts
- A full OPcache makes scripts fail to run
- Each PHP-FPM pool gets its own memory_consumption budget
- OPcache memory needs grow with request traffic