31

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.

12
  • I am truly curious as to why you would want to do this? Aug 23, 2009 at 22:10
  • For the small performance gains. I like to keep my hard drive(s) partitioned according to usage. I have one partition for the OS and applications, one for the users folder, one for documents, one for media (music, movies, etc.) and one for swapfiles. In my experience, keeping the swap files separate from the rest of the system keeps disk fragmentation low. My preference would be to have swap on a dedicated drive, but another partition will usually suffice.
    – e.James
    Aug 23, 2009 at 22:20
  • 4
    Fair enough - However partitions on the same drive actually causes more work for the drive itself, however partitions on different drives provide a performance gain. The hard drive has to do more work when jumping across partitions on a single drive. I only ask because I have yet to have fragmentation and performance issues on my Mac after almost 2 years of usage out of the box, and when I see these posts they interest me. Aug 23, 2009 at 22:28
  • 1
    I'm not sure why I can't post an answer (101 rep, which — if I can remember my maths — is more than the 10 which the protected state requires), but I found an non-wait4path solution, thanks to what Applicorn's Xupport modified for me. I'll post a full answer once I figure out how to, but the short of it is to change the last program argument to just the new path (e.g. <string>/Volumes/swap/.vm/swapfile</string>), change the OnDemand key to <true/>, and add a StartOnMount key to the end with a value of <true/>. P.S. This solution works fine in Lion (for me, at least). Apr 22, 2012 at 2:20
  • 1
    @Slipp Douglas: Looks legit to me. The StartOnMount flag was added in 10.5 according to: mactech.com/articles/mactech/Vol.25/25.10/…
    – e.James
    Apr 23, 2012 at 15:05

8 Answers 8

10
+150

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,}
6
  • Are you certain that the swapfile is actually being moved to the partition with this setup? When I tried this approach originally, dynamic_pager would load before the secondary partitions had been mounted. The system would fake its way through by creating a symbolic link to partition2 in the /Volumes directory which simply pointed back to /private/var/vm. You could identify the failure by doing ls -al in the /Volumes directory, where you would see both "partition2" (the symbolic link) and "partition2 1" (your actual partition).
    – e.James
    Sep 18, 2009 at 14:34
  • Either way, +1 for the technique to convert plist files to & from binary format. com.apple.dynamic_pager.plist was in plain text format in 10.5.x, but in binary format as of 10.6. Which is part of my problem. I've been modifying plist files using the Property List Editor app that comes with Xcode, and maybe that's why things didn't work. I'll give plutil a try and see if it gets me any further.
    – e.James
    Sep 18, 2009 at 14:55
  • I can't test it with another partition at the moment, however during my tests I made dynamic_pager creating swapfiles on a thumbdrive by using the above technique.
    – dblu
    Sep 18, 2009 at 19:43
  • I was able to make the original technique work, thanks to your suggestion to use plutil for the conversions. I posted the complete solution in the question (since I don't have enough rep to add it to your answer). See my note #1 for a detailed description of the problems I ran into with just modifying the plist.
    – e.James
    Sep 18, 2009 at 20:45
  • Anyway, thank you for the answer. You put together an excellent set of instructions, and you pointed me in the right direction so I have marked it as accepted. Cheers! :)
    – e.James
    Sep 18, 2009 at 20:49
3

I've adopted this idea and taken it a bit further by addressing the growth and reclamation strategies.

Details at http://www.crypticide.com/dropsafe/article/3848 ; I would post a link to the "dynamicpagerwrapper" GoogleCode project page, but the blog tells me that I don't have enough reputation points...

2
3

just a question: why not just editing the .plist file adding wait4path, instead of using the intermediate dynamic_pager_init ?

something like this:

EDIT: as explained in the comment by e.James and my following comment, the immediately following XML block is not good, both because there's an error (missing &&) and because only the first argument of the array ProgramArguments it's parsed as the program to run!

but.. (scroll down)

 ...
13     <key>ProgramArguments</key>
14     <array>
15         <string>/bin/wait4path</string>
16         <string>/Volumes/Swap/</string>
17         <string>/sbin/dynamic_pager</string>
18         <string>-F</string>
19         <string>/Volumes/Swap/.vm/swapfile</string>
20     </array>
 ...

end of the wrong xml block


this XML block should work instead:

   ...
    13     <key>ProgramArguments</key>
    14     <array>
    15         <string>/bin/bash</string>
    16         <string>-c</string>
    17         <string>/bin/wait4path /Volumes/Swap/ &amp;&amp; /sbin/dynamic_pager -F /Volumes/Swap/.vm/swapfile</string>
    18     </array>
     ...

please keep in mind that i still had not enough time to safely try this setting, but i tried to run various other shell commands launched in the same way, and everything should work as expected

How it works:

base: executing wait4path /path && command means that command is run only if wait4path ends and exits without errors, and this happens only when /path is an available path, so we can safely tell dynamic_pager to use that volume for swapfiles

1) as written in launchd.plist manpage, the keys Program and ProgramArguments are mapped to an execvp call, that means that everything but the first string in the array is treated as an argument for the first string in the array, the program to run;

2) as written in bash manpage, there is a bash -c <string> option to run the string passed as commands

1+2 = 3) what happens using this command line in a launchd plist ??

/bin/bash -c "wait4path /Volumes/Swap/ && /sbin/dynamic_pager -F /Volumes/Swap/.vm/swapfile"

/bin/bash is the program to run, -c is the first argument and the double quoted string is the second argument

I guess it should work exactly as your solution, without the intermediate script: launchd will start the service, that will wait for the given path and then launch dynamic_pager..

Please note that:
* the string that you want to execute should be double quoted if you run bash -c in Terminal, but it's not double quoted in the plist file! (i guess because it's already declared as a string with the proper tag)
* the two & in the string must be changed to &amp; in the plist file

PS: as always, proceed at your own risk, i take no responsibility for problems you may have using this setting !

thanks for sharing your work with us

5
  • That is an interesting idea. I'm not sure if it is "legal" to put more than one program into the ProgramArguments array, but it is certainly worth a shot. Have you tried it out?
    – e.James
    Jul 13, 2010 at 14:57
  • Sorry, there's an error in my previous post, my idea was to run the following command line (note the && that was missing): wait4path /Volumes/Swap/ && /sbin/dynamic_pager -F /Volumes/Swap/.vm/swapfile if someone finds a way to "format" that line so that launchd will like it, i guess it should work (i'm thinking about it, maybe calling /bin/bash an passing the rest as arguments ?); more explanations about the Program and ProgramArguments fields are available in the launchd.plist manpage, and that will lead to execvp(3) manpage. I'm reading & thinking, if someone is faster please post :)
    – ekl
    Jul 13, 2010 at 16:07
  • i edited the previous post with a solution that should work, please comment if you see any kind of error or whatever may not work properly, thanks!
    – ekl
    Jul 13, 2010 at 23:52
  • I tried it out on my laptop, and it seems to work. I'll keep an eye on it for a couple of days to be sure, but it looks like you've simplified the whole process immensely! Nice work :)
    – e.James
    Jul 14, 2010 at 8:03
  • Your simplified method is working like a charm on my laptop. Thank you! I will update the main question to incorporate your solution.
    – e.James
    Jul 29, 2010 at 11:09
2

I know it has been a while since this article was written but I thought I would add my own little item down here for for those who want to do this as well…

I have used the above trick to move my swap files off to another internal drive (my boot drive is SSD with MLC chips, so moving vm off can save the life expectancy). Anyway, after creating the new volume I had a Swap volume in Finder that I am never going to use in Finder itself, so I decided to make the volume invisible to Finder. You need Apple's Developer Toolkit installed. Then type:

/Developer/Tools/SetFile -a V /Volumes/Swap/

…and replace /Volumes/Swap with whatever you named your volume. Restart Finder and presto, no more Swap volume in Finder!

1

You can use wait4path to wait for the volume to mount; otherwise, launchd will restart your dynamic_pager_init script over and over and over until it does...

1
  • Brilliant! I used wait4path instead of the if/grep combination, and that cleans things up quite nicely. Thank you for the tip.
    – e.James
    Dec 12, 2009 at 22:05
1

Maybe we can use Xupport to do those dirty job for us :) http://www.applicorn.com/

Virtual Memory Optimizer:

Change the swap files location In Mac OS X the virtual memory information are stored in the so called "Swapfiles". Because the swapfiles are the most interactive system files, it makes sense to put them on a separate partition. It is recommended to store the swap files on the first partition of your fastest internal hard disk. The recommended minimum partition size should be about 3 or 4 times lager than the physical built-in memory size (e.g 1 GB physical memory = 4 GB swap partition). Recommendations and instructions for an optimal system performance:

1. Re-partition your hard disk with a swap volume as FIRST partition (using the Mac OS X Install DVD). WARNING: RE-PARTITIONING A HARD DISK WILL EREASE ALL EXISTING DATA!

2. Restore your system data or install new system on the system partition.

3. Boot from the system partition.

4. If you want your swap volume to be invisible to the Finder: • Launch Xupport and choose "Settings" • Enable "Show hidden files and folders" and restart the Finder • Rename the swap volume from "swap" to ".swap" (The dot makes it invisible to the Finder) • Disable "Show hidden files and folders" and restart the Finder again

5. Select the new swap partition under "Swap Storage Volume". Then, press the "Set" button to apply the new swap file location settings (Restart required).

BTW, it works for me. Snow Leopard 10.6.2 @ Macbook Pro 2.4GHz, 4GB Ram, 500GB HD

2
  • Looks promising. Thank you for the link and detailed instructions!
    – e.James
    Jan 31, 2010 at 11:22
  • applicorn.com - 404
    – pkoch
    Mar 26, 2012 at 13:58
1

This is most likely an unwanted answer (since I can't comment after Diago), but why really do you insist this will give small performance gains? I've went through a discussion on apple forums and conclusion was that this is not a good idea at all. And I was very resistant on abandoning it. Could you come up with data proving that at least for yourself, or is it just a "feeling"?

From every time I used swap even on linux, back 10 years ago, and nowadays on ubuntu, I could never see improvements on performance. My reason for wanting it was to prevent issues with free space on OSX and, on linux, for being able to hibernate. That's all swap is to me.

But I've never really did deeper research either on my own or in the interwebs.

2
  • That's a valid criticism. I have no data to support my claims :)
    – e.James
    Feb 23, 2010 at 4:25
  • Cool. So, eventually, you might give up on going through all this trouble as well! :P
    – cregox
    Feb 23, 2010 at 19:39
1

This isn't an answer, but perhaps a very useful follow-up supplement. Apple provides a free plist editor here PlistEdit Pro. It allows you to edit these files safely. Looks as if you could just change the argument with the value /private/var/vm/swapfile to something like /Volumes/OtherDrive/vm/myswapfilename to move the swap files somewhere else...

Again I have not tested this...

1
  • It's a good thought, and the first thing I started with when I went down this route. The problem is that the swap partition is not always mounted at the point in time when dynamic pager launches. See note #1 in the question itself for details about what I mean.
    – e.James
    Oct 30, 2010 at 2:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .