Caches and purging in macOS Tahoe

We judge our Macs on the responsiveness of their graphical interface. Open a folder of images in a Finder Gallery view and start scrolling through its contents. If each image preview took a couple of seconds to render, we’d be unhappy at that sluggish performance. For QuickLook to generate each preview image whenever it needs to be rendered would take time and plenty of computing power. The solution is to generate each preview once, and to cache those images both on disk and in memory.

Caching data to disk is one of the tasks common to many components in macOS, including apps like Safari and Mail. As with third-party apps, each has to manage its own caches, tracking how much space they’re using, and ensuring that’s used effectively without running free disk space too low.

deleted

Those disk caches are optional extras, and when macOS needs to find additional free space they’re candidates for deletion, or purging, along with other non-essential features such as local snapshots made by Time Machine. The disk space that could be freed by their removal is thus considered to be purgeable space, and is managed by the deleted service in the subsystem com.apple.cache_delete.

deleted only manages the caching services listed in the property lists in /System/Library/CacheDelete. As that’s in the SSV it can’t be modified or added to, so third-party apps that want their caches to be included can set the isPurgeable flag on those files to true to add them to the com.apple.fspurgeable_data list.

Each caching service keeps an account of its cached files and the total space they take, some periodically refreshing that using a background service scheduled and dispatched by DAS-CTS. When deleted needs to know how much space could be freed by purging those caches, it obtains the current figure from each of those services in turn. It can then work out whether sufficient space could be purged to meet a request from macOS, thus whether that request can be accommodated by realising purgeable space. If it can, it’s then up to deleted to call for the selected caching services to purge their caches to provide the free space needed.

Will purging work?

When a request is made to deleted to free purgeable space to enable an operation such as copying a file into the volume, you’ll see a succession of entries like
0.654212 com.apple.cache_delete com.apple.fspurgeable_data : 0
giving the purgeable space available for each caching service. For example, when there are Time Machine snapshots that could be purged, its log entry might read
0.654500 com.apple.cache_delete com.apple.TMCacheDelete : 94876508160

Those are totalled in
0.654501 com.apple.cache_delete CACHE_DELETE_SHARED_PURGEABLE : 94876508160
and summarised in the entries
00.654638 com.apple.cache_delete <<<Query Result from client cache (u: 3, ET: 0.03277024999999999): "/Volumes/TestVolume1 : 94.88 GB"
0.654770 com.apple.cache_delete CACHE_DELETE_TOTAL_AVAILABLE : 94876561408

If the decision is made to proceed with the purging, that’s recorded with entries listing the caching services to be used:
0.657438 com.apple.cache_delete PurgeOperation on volume [private], registered services:
0.657438 com.apple.cache_delete com.apple.TMCacheDelete
0.657439 com.apple.cache_delete com.apple.deleted_helper

Purging

The purge is then started with the information
0.658195 com.apple.cache_delete urgencyLimit: 3, info at start: {
"CACHE_DELETE_AMOUNT" = 7707074560;
"CACHE_DELETE_CALLING_PROCESS" = Finder;
"CACHE_DELETE_FREESPACE_GOAL" = 12893556736;
"CACHE_DELETE_ID" = "com.apple.cache_delete";
"CACHE_DELETE_MEASURE_ELAPSED_TIME" = 0;
"CACHE_DELETE_QOS" = 25;
"CACHE_DELETE_TOKEN" = "C58DB946-8B85-42AF-9291-0D8AF092002E";
"CACHE_DELETE_URGENCY_LIMIT" = 3;
"CACHE_DELETE_VOLUME" = "/Volumes/TestVolume1";}

In this case, purging snapshots takes several seconds work by APFS, during which deleted continues to monitor purgeable and free space. When that’s complete it writes an entry to summarise the result
9.616316 com.apple.cache_delete Purge Result: 94876618752 bytes on: [CacheDeleteDaemonVolume] at: /Volumes/TestVolume1 [/dev/disk7s1 : apfs] freespace: 100063100928 (100.06 GB), initialFreespace: 5186482176 (5.19 GB), used: 1048576 (1.05 MB), total size: 100189175808 (100.19 GB)PRIMARY, diskRef: 0xc39018a20

In other cases, purging sufficient space may require a series of phases run at different levels of urgency, starting at 3, and targeting groups of caching services, until sufficient free space has been created to complete the action that needed the additional free space.

There are some occasions when, even though there’s ample free space, multiple rounds of purging may be undertaken. One of the most obvious is when installing a macOS update.

Key points

  • Many apps and services in macOS cache data to disk to improve performance.
  • Cached data is optional, so when additional free space is needed, it may be purged, thus accounting for purgeable space. This can also include any Time Machine local snapshots.
  • Each caching service maintains accounts of its caches and the space they occupy.
  • When purgeable space is required, deleted (subsystem com.apple.cache_delete) first discovers purgeable space for each caching service, to determine whether it’s sufficient.
  • If it is, and the decision is taken to purge caches, caching services are called on to free up space by purging their caches as required.
  • Purging may then take place in phases until sufficient space has been freed.
  • Purging is frequent during installation of macOS updates, even when there’s ample free space available.