Use APFS VM Volume From Another Disk
Due to the sad demise of my main machine, I'm booting a much less capable system from an external drive to keep myself going while I await a replacement. The machine itself has its own internal drive. Both the machine's own internal drive, and my recovered (now external) drive, are formatted APFS, and both have the full set of system volumes (preboot, recovery and VM).
The problem is, when booting from the external drive, macOS wants to store swapfiles on it, even though the performance is poor when doing this, especially since this emergency setup has a lot less RAM making swapping a lot more likely.
What I'd like to know is; can I tell macOS Mojave to mount the internal drive's VM volume and use that for swap-files, rather than using the external disk?
One oddity is that although the external drive has its own VM volume (not that I want to use it), macOS Mojave isn't utilising that either, instead it's storing swap-files under /vm
, rather than mounting the VM volume at /private/var/vm
as normal.
In case it's easier to visualise, my drives look like this, where disk0
is internal, and disk2
is external, and was pulled from my dead machine:
diskutil list
/dev/disk0 (internal, physical):
#: TYPE NAME SIZE IDENTIFIER
0: GUID_partition_scheme *320.1 GB disk0
1: EFI EFI 209.7 MB disk0s1
2: Apple_APFS Container disk1 319.9 GB disk0s2
/dev/disk1 (synthesized):
#: TYPE NAME SIZE IDENTIFIER
0: APFS Container Scheme - +319.9 GB disk1
Physical Store disk0s2
1: APFS Volume Macintosh HD 34.4 GB disk1s1
2: APFS Volume Preboot 41.8 MB disk1s2
3: APFS Volume Recovery 507.4 MB disk1s3
4: APFS Volume VM 20.5 KB disk1s4
/dev/disk2 (external, physical):
#: TYPE NAME SIZE IDENTIFIER
0: GUID_partition_scheme *1.0 TB disk2
1: EFI EFI 209.7 MB disk2s1
2: Apple_APFS Container disk3 1000.0 GB disk2s2
/dev/disk3 (synthesized):
#: TYPE NAME SIZE IDENTIFIER
0: APFS Container Scheme - +1000.0 GB disk3
Physical Store disk2s2
1: APFS Volume macOS 102.5 GB disk3s1
2: APFS Volume Preboot 64.3 MB disk3s2
3: APFS Volume Recovery 1.0 GB disk3s3
4: APFS Volume VM 20.5 KB disk3s4
5: APFS Volume Users 321.0 GB disk3s5
To clarify; I'm not looking to disable swapping entirely, but to use the internal drive as the swap-file location. Indeed, swapping is necessary on the older machine I'm using, as it was never used for much more than a media-centre, and only has 4gb of RAM, which fills fast!
I believe I've found a solution to this thanks to an answer to a similar question, the process that is responsible for the swap-files is /sbin/dynamic_pager
, which is triggered by a launchd
task found at /System/Library/LaunchDaemons/com.apple.dynamic_pager.plist
. Since this file is located in /System
it means that this solution requires System Integrity Protection to be disabled, and for Catalina you will need to perform the changes from your recovery volume.
First step is to take a backup of the original plist:
cp /System/Library/com.apple.dynamic_pager.plist /System/Library/com.apple.dynamic_pager.plist.orig
Now we want to modify the command that is executed. In the original it will look like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>EnableTransactions</key>
<true/>
<key>Label</key>
<string>com.apple.dynamic_pager</string>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
</dict>
<key>POSIXSpawnType</key>
<string>Interactive</string>
<key>ProgramArguments</key>
<array>
<string>/sbin/dynamic_pager</string>
</array>
</dict>
</plist>
I modified my ProgramArguments
section to the following:
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>-c</string>
<string>diskutil mount -mountPoint /private/var/vm disk1s4 && /sbin/dynamic_pager -F /private/var/vm/swapfile</string>
</array>
This now runs two commands, the first to mount the internal VM volume at /private/var/vm
and the second is a modified call to dynamic_pager
telling it to create swapfiles at the new location.
NOTE: In my case the VM volume was disk1s4
, and while this should be the case for most systems, you should double check with diskutil list
first and modify the new command accordingly.
To activate the changes, either restart or, if you're sure you aren't using a swap-file at the moment, you can unload and reload the launchd task immediately:
launchctl unload /System/Library/com.apple.dynamic_pager.plist
launchctl load /System/Library/com.apple.dynamic_pager.plist
The new swapfile location should now be set, and if necessary you can remove any leftover swapfile(s) (in my case at /vm
).
UPDATE: Simpler method
It occurred to me that there may be a simpler solution to this problem; since the dynamic pager launchd task doesn't supply a specific location for swapfiles, it seems it will choose in order of preference, with /private/var/vm
being preferred if available. To this end it may be possible to force the use of the internal drive's VM volume like so:
- Get the VM volume's UUID (
diskutil info disk1s4
) - Run
sudo vifs
- Add a line like so:
UUID=9e2cd41c-1566-11ea-9237-ef9cfb4e0fac /private/var/vm apfs rw,nobrowse,union
swapping in your volume's UUID
This should cause your system to automatically mount your VM volume at /private/var/vm
, and since this will occur before the dynamic pager runs, it should see and select this location, with no need to disable SIP or edit its launch daemon.