← All posts

Why OPcache Wasted Memory Grows With Docket Cache

By · · 7 min read

If you open Docket Cache > OPcache and watch it for a few days, you may see the Current Wasted number go up and up. Turn the object cache off, and it stays low. Users have asked us about this, and they are right to ask. This post explains what is going on, honestly, what we changed in Docket Cache 26.04.12, and what you can do about it.

What wasted memory is#

OPcache keeps compiled PHP files in a fixed block of shared memory. When a PHP file changes, OPcache cannot update its copy in place. It marks the old copy as wasted, and keeps the new copy in a different part of the memory block.

The wasted copy is not freed on its own. OPcache only frees it when it restarts, which empties the whole block in one go. After a restart, every PHP file has to be compiled again, so the site is a little slower for a short time.

Our post How Docket Cache Uses OPcache explains the basics.

Why it grows with Docket Cache#

WordPress, themes and plugins are PHP files that almost never change, except during an update. So without an object cache, OPcache wastes very little memory.

Docket Cache is different. Its cache files are PHP files too, and they change all the time. Each time WordPress or a plugin saves a value with wp_cache_set(), Docket Cache writes the cache file again, and tells OPcache to drop the old copy. Every write leaves one wasted copy behind. On a busy site, that can be thousands of writes a day.

Up to version 26.04.11, Docket Cache did this even when the new value was exactly the same as the old one. WordPress and plugins often save the same value again, so many of those writes were not needed at all.

So yes, the growth comes from Docket Cache, and it is not a bug or a wrong setting. It is how OPcache handles files that change, and Docket Cache uses OPcache for files that change.

What 26.04.12 changes#

Since version 26.04.12, Docket Cache checks the cache file before it writes. If the file already holds the same value, it leaves the file alone. Nothing is written, so OPcache has no old copy to waste.

To make the check fast, each cache file now holds a short fingerprint of its value. Docket Cache compares the fingerprints, not the whole values, so the check stays fast for large values too.

On one of our test sites, we saved the same 200 values again and again.

26.04.11 26.04.12
OPcache memory wasted each time 644 KB 0 KB
Time for each save 0.18 ms 0.04 ms

There are limits, and we want to be clear about them.

The check is on by default. To turn it off, set Skip Unchanged Cache Writes to Disable in Docket Cache > Configuration, or add this line to wp-config.php.

define('DOCKET_CACHE_SKIP_UNCHANGED', false);

When it matters#

A high Current Wasted number on its own does no harm. The wasted memory just sits there.

It starts to matter when the memory block runs out of free space. OPcache then checks the wasted share. If it is above opcache.max_wasted_percentage, which is 5% by default, OPcache restarts and empties itself. If it is below, new files are simply not cached until there is room.

So the real questions are these.

If there is plenty of free memory, a growing wasted number only means that a restart will come later. If free memory runs out every few hours, OPcache restarts often, and that costs more than it saves.

How to keep it under control#

Update to 26.04.12#

Update Docket Cache from the Plugins screen. You do not need to change any settings. The update also has other fixes, which we list at the end of this post.

Give OPcache more room#

The bigger the memory block, the longer it takes to fill, and the fewer restarts you get.

opcache.memory_consumption=256
opcache.max_accelerated_files=65407
opcache.max_wasted_percentage=10

Restart PHP after you change these settings. The OPcache Extension page explains each one.

Cache less of what changes often#

Some cache groups change on almost every request, such as counters, sessions and rate limits. Saving them as PHP files wastes OPcache memory, and they gain very little from it.

  1. Turn on the Cache Log option in Docket Cache > Configuration for a short time.
  2. Look for the groups and keys that are written again and again. Select a row and click View to see what the cache file holds.
  3. Leave them out of the cache with DOCKET_CACHE_IGNORED_GROUPS or DOCKET_CACHE_IGNORED_KEYS in wp-config.php. They are then only kept in memory for the current request.
define('DOCKET_CACHE_IGNORED_GROUPS', ['counts', 'plugins', 'themes', 'my-plugin-counters']);

Keep counts, plugins and themes in the list. They are the default, and your list replaces it.

Turn the Cache Log off again when you are done.

Keep the cache files out of OPcache#

If your site writes to the cache so often that OPcache keeps restarting, you can tell OPcache to skip the Docket Cache folder with opcache.blacklist_filename. Create a text file that lists the folder, for example /etc/php/opcache-blacklist.txt.

/path/to/wordpress/wp-content/cache/docket-cache/

Then point OPcache at it.

opcache.blacklist_filename=/etc/php/opcache-blacklist.txt

Docket Cache still works. The cache files are then read from disk and compiled on each request, so reads are slower, but OPcache memory stays for WordPress, your theme and your plugins.

When Docket Cache is not the right tool#

We built Docket Cache for sites that cannot use Redis or Memcached, which is most shared hosting. For those sites, it is still a big step up from no object cache at all.

But for a very busy site whose cache changes all the time, an in-memory cache like Redis is a better fit. Redis frees the memory of an old value as soon as it is replaced, so it does not have this problem. Our post Docket Cache, Redis Or Memcached? helps you decide.

Other fixes in 26.04.12#

The same release has more fixes. The first two came from reports on our support forum. Thank you to everyone who wrote in and tested the fixes.