Macos – Moving the swapfiles to a dedicated partition in Snow Leopard

macmacososx-snow-leopardpartitioningswap

I have been able to move Apple's virtual memory swapfiles to a dedicated partition on my hard drive up until now. The technique I have been using is described in a thread on forums.macosxhints.com.

However, with the developer preview of Snow Leopard, this method no longer works. Does anyone know how it could be done with the new OS?

Update: I have marked dblu's answer as accepted even though it didn't quite work because he gave excellent, detailed instructions and because his suggestion to use plutil ultimately pointed me in the right direction. The complete, working solution is posted here in the question because I don't have enough reputation to edit the accepted answer.

Update #2: Changed the procedure to illustrate ekl's technique, which greatly simplifies the whole thing by eliminating the need for an intermediate shell script:

Complete solution:

1. Open Terminal and make a backup copy of Apple's default dynamic_pager.plist:

$ cd /System/Library/LaunchDaemons
$ sudo cp com.apple.dynamic_pager.plist{,_bak}

2. Convert the plist from binary to plain XML:

$ sudo plutil -convert xml1 com.apple.dynamic_pager.plist

3. Open the converted plist with your text editor of choice. (I use pico, see dblu's answer for an example using vim):

$ sudo pico -w com.apple.dynamic_pager.plist

It should look as follows:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs$
<plist version="1.0">
<dict>
    <key>EnableTransactions</key>
    <true/>
    <key>HopefullyExitsLast</key>
    <true/>
    <key>Label</key>
    <string>com.apple.dynamic_pager</string>
    <key>OnDemand</key>
    <false/>
    <key>ProgramArguments</key>
    <array>
        <string>/sbin/dynamic_pager</string>
        <string>-F</string>
        <string>/private/var/vm/swapfile</string>
    </array>
</dict>
</plist>

4. Modify the ProgramArguments array (lines 13 through 18) to use the wait4path shell command (as suggested by ZILjr) prior to launching dynamic_pager. See note #1 for details on why this is necessary. In the following example, my partition is called 'Swap', and I chose to put the swapfiles in a hidden directory on that partition, called '.vm' be sure that the directory you specify actually exists. The XML should look as follows:

<key>ProgramArguments</key>
<array>
    <string>/bin/bash</string>
    <string>-c</string>
    <string>/bin/wait4path /Volumes/Swap/ &amp;&amp;
/sbin/dynamic_pager -F /Volumes/Swap/.vm/swapfile</string>
</array>

5. Save the plist, and return to the terminal prompt. Using pico, the commands would be:

<ctrl+o> to save the file
<enter>  to accept the same filename (com.apple.dynamic_pager.plist)
<ctrl+x> to exit

6. Convert the modified plist back to binary:

$ sudo plutil -convert binary1 com.apple.dynamic_pager.plist

7. Restart your Mac. If you run into trouble, switch to verbose startup mode by holding down Command-v immediately after the startup chime. This will let you see all of the startup messages that appear during startup. If you run into even worse trouble (i.e. you never see the login screen), hold down Command-s instead. This will boot the computer in single-user mode (no graphical UI, just a command prompt) and allow you to restore the backup copy of com.apple.dynamic_pager.plist that you made in step 1.

8. Once the computer boots, fire up Terminal and verify that the swap files have actually been moved:

$ cd /Volumes/Swap/.vm
$ ls -l

You should see something like this:

-rw-------  1 someUser  staff  67108864 18 Sep 12:02 swapfile0

9. Delete the old swapfiles:

$ cd /private/var/vm
$ sudo rm swapfile*

10. Profit!

Note 1

Modifying the arguments to dynamic_pager in the plist without using wait4path does not always work, and when it fails, it does so in a spectacularly silent way. The problem stems from the fact that dynamic_pager is launched very early in the startup process. If your swap partition has not yet been mounted when dynamic_pager is first loaded (in my experience, this happens 99% of the time), then the system will fake its way through. It will create a symbolic link in your /Volumes directory which has the same name as your swap partition, but points back to the default swapfile location (/private/var/vm). Then, when your actual swap partition mounts, it will be given the name Swap 1 (or YourDriveName 1). You can see the problem by opening up Terminal and listing the contents of your /Volumes directory:

$ cd /Volumes
$ ls -l

You will see something like this:

drwxrwxrwx  11 yourUser  staff   442 16 Sep 12:13 Swap -> private/var/vm
drwxrwxrwx  14 yourUser  staff     5 16 Sep 12:13 Swap 1 
lrwxr-xr-x   1 root      admin     1 17 Sep 12:01 System -> /

Note that this failure can be very hard to spot. If you were to check for the swapfiles as I show in step 12, you would still see them! The symbolic link would make it seem as though your swapfiles had been moved, even though they were actually being stored in the default location.

Note 2

I was originally unable to get this to work in Snow Leopard because com.apple.dynamic_pager.plist was stored in binary format. I made a copy of the original file and opened it with Apple's Property List Editor (available with Xcode) in order to make changes, but this process added some extended attributes to the plist file which caused the system to ignore it and just use the defaults. As dblu pointed out, using plutil to convert the file to plain XML works like a charm.

Note 3

You can check the Console application to see any messages that dynamic_pager_init echos to the screen. If you see the following lines repeated over and over again, there is a problem with the setup. I ran into these messages because I forgot to create the '.vm' directory that I specified in dynamic_pager_init.

com.apple.launchd[1]  (com.apple.dynamic_pager[176]) Exited with exit code: 1
com.apple.launchd[1]  (com.apple.dynamic_pager) Throttling respawn: Will start in 10 seconds

When everything is working properly, you may see the above message a couple of times only, and then no more of the "Throttling respawn" messages. This means that the system did have to wait for the partition to load, but in the end it was successful.

Best Answer

NOTE: See (also) a corrected/improved answer in the question itself.


Following solution worked for me:

Open a terminal and backup com.apple.dynamic_pager.plist which you're going to change in a second:

$ cd /System/Library/LaunchDaemons
$ sudo cp com.apple.dynamic_pager.plist{,_bak}

convert binary plist to xml:

$ sudo plutil -convert xml1 com.apple.dynamic_pager.plist

and open it with your favorite text editor

$ sudo vim com.apple.dynamic_pager.plist

it'll look something like this:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 <plist version="1.0">
 4 <dict>
 5     <key>EnableTransactions</key>
 6     <true/>
 7     <key>HopefullyExitsLast</key>
 8     <true/>
 9     <key>Label</key>
10     <string>com.apple.dynamic_pager</string>
11     <key>OnDemand</key>
12     <false/>
13     <key>ProgramArguments</key>
14     <array>
15         <string>/sbin/dynamic_pager</string>
16         <string>-F</string>
17         <string>/private/var/vm/swapfile</string>
18     </array>
19 </dict>
20 </plist>

In line 17 modify /private/var/vm/swapfile (e.g. /Volumes/partition2/swapfile), save and close your editor (":x" will do both in vim).

convert the plist file back to binary:

$ sudo plutil -convert binary1 com.apple.dynamic_pager.plist

After rebooting your Mac you should find the swapfiles in the directory you specified.

If you run into any problems you can restore the backup you created in the first step with:

$ cd /System/Library/LaunchDaemons
$ sudo cp com.apple.dynamic_pager.plist{_bak,}