Where does macOS get its volume free space figures from?

Have you ever wondered where apps like Disk Utility get their figures for free space on volumes, particularly those for purgeable and available space? If you thought they got them from APFS, then I’m sorry to disappoint, but their source is the space management feature in macOS, its CacheDelete subsystem.

To look at this in more depth, I generated a file system event sufficient to trigger CacheDelete to recalculate its measures of free space, on a VM with log privacy disabled, no iCloud connection, and with Time Machine backups turned off.

CacheDelete’s service daemon is deleted, which also has a helper process deleted_helper. They rely on a set of definitions stored in /System/Library/CacheDelete, currently 32 short property lists used to define the services most likely to have purgeable data, and set how CacheDelete should purge those files. As those property lists are stored on the System volume, they can’t be changed or augmented by the user or third-parties.

CacheDelete forceRefresh

In this example, the file system event was deleting a large file by emptying the Finder’s Trash. The sequence starts with the Finder posting an EmptyingTrash event to the deleted daemon. This becomes a CacheDelete event key of CACHE_DELETE_EMPTY_TRASH and a forceRefresh request for deleted. Once it has validated mountpoints for volumes, deleted starts work, setting the urgency to 3 and the query path to SLOW, to perform a thorough refresh.

cachedeletetrash1

deleted then calls its helper to evaluate the fsPurgeable total, the number and size of files for 10 standard services that are marked as being purgeable in the file system, using an inode flag. This is reported back in a total broken down by service:

  • /System/Volumes/Data freespace: 30861533184
  • CACHE_DELETE_AMOUNT = 10989568
  • CACHE_DELETE_ITEMIZED_PURGEABLE =
    • CACHE_DELETE_TOTAL_FSPURGEABLE = 10989568
    • com.apple.fspurgeable_data = 10756096
    • com.apple.fspurgeable_document = 233472
  • [others zero].

cachedeletetrash2

In the next phase, the deleted daemon checks a longer list of around 39 services, including those in the first list, with the Service Info Amount for each. These figures represent the space required for items considered to be nonpurgeable and those that are shared purgeable, and CacheDelete updates each in its list of nonpurgeable space, to arrive at a total for the volume.

  • CACHE_DELETE_NONPURGEABLE_AMOUNT = 49331272
  • CACHE_DELETE_SHARED_PURGEABLE = 14124800
  • CACHE_DELETE_TOTAL_AVAILABLE = 14124800
  • CACHE_DELETE_ITEMIZED_NONPURGEABLE =
    • com.apple.logd.cachedelete = 49331272
  • com.apple.AssetCache.builtin.CacheDelete = 73728
  • com.apple.coresymbolicationd.cache-delete = 49152
  • [others zero].

That’s followed by a further round of checks of purgeable space by each service, and another set of reports on space, before deleted calls its helper to re-evaluate fsPurgeable for the ten standard services.

cachedeletetrash3

CacheDelete next builds a list of recently used apps, which is used by deleted to check for further purgeable space, including that inside their containers. This inevitably involves negotiating TCC and privacy protection, depending on the app. That’s followed by a round of checks on plug-ins, based on PlugInKit.

With all the services and apps checked, deleted arrives at a summary report giving totals and a detailed breakdown.

  • CACHE_DELETE_FREESPACE = 30861533184
  • CACHE_DELETE_SHARED_PURGEABLE = 15972096
  • CACHE_DELETE_TOTAL_AVAILABLE = 15972096
  • CACHE_DELETE_TOTAL_FSPURGEABLE = 10989568
  • CACHE_DELETE_NONPURGEABLE_AMOUNT = 49331272
  • CACHE_DELETE_ITEMIZED_NONPURGEABLE =
    • com.apple.logd.cachedelete = 49331272
  • com.apple.AssetCache.builtin.CacheDelete = 73728
  • com.apple.cache_delete_app_container_caches = 12288
  • com.apple.coresymbolicationd.cache-delete = 18
  • others zero.

cachedeletetrash0

On the fairly minimal Data volume of a VM running Ventura 13.3.1 without iCloud or Time Machine snapshots, the whole sequence took 1.3 seconds and thousands of log entries. The total space occupied by files marked as being purgeable was just under 11 MB, with slightly less than 16 MB designated as shared purgeable, and 49 MB of nonpurgeable space. On most Data volumes, those figures will be increased substantially by Time Machine snapshots, but not those made by third-party apps (as they aren’t purgeable by CacheDelete). Purgeable iCloud space remains more of a mystery.

Checking free space

Apps, including Disk Utility and those third-party apps that use the URLResourceValue volumeAvailableCapacityForImportantUsage and similar API calls, derive purgeable and available space from CacheDelete’s latest figures. This is easy to confirm, as when the app calls for those figures, CacheDelete’s entries in the log reveal that it’s providing them. Use the predicate
subsystem == "com.apple.cache_delete"
to see its numerous entries.

You may be surprised to learn that when you open the Finder’s Get Info dialog on a volume, no call is made to CacheDelete to obtain its latest figures for purgeable or available space. As there’s no indication in the log that those figures are obtained from anywhere comparable, it’s most likely that the Finder maintains its own values, and updates them periodically from CacheDelete. What is strange, though, is that when the Finder posts a file system event that’s inevitably going to result in CacheDelete refreshing its authoritative figures, the Finder doesn’t appear to obtain the updated figures once CacheDelete has compiled them.

This may explain why the Finder’s Get Info figures can become badly out of kilter with those shown in Disk Utility and third-party apps. It emphasises the fact that, if you want accurate and up-to-date figures for free space, you should ignore the Finder and check in Disk Utility or elsewhere. The Finder is lost.