Moving the swapfiles to a dedicated partition in Snow Leopard

27,727

Solution 1

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,}

Solution 2

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

Solution 3

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!

Solution 4

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...

Solution 5

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.

Share:
27,727

Related videos on Youtube

e.James
Author by

e.James

Updated on September 17, 2022

Comments

  • e.James
    e.James over 1 year

    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.

    • Admin
      Admin over 14 years
      I am truly curious as to why you would want to do this?
    • Admin
      Admin over 14 years
      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.
    • Admin
      Admin over 14 years
      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.
    • Admin
      Admin over 14 years
      I tend to work my machine pretty hard; split between Cocoa development, 3D rendering and Photoshop work, and a little casual gaming when I have the time. I'm might be a little too concerned with tiny performance issues, but I spend so much time sitting in front of the machine that I've become sensitive to them :)
    • Admin
      Admin over 14 years
      Snow Leopard is stil under NDA until the 28th. All the developer previews are under NDA as well.
    • Admin
      Admin over 14 years
      I suppose you're right. Perhaps that's why there are no answers here. I hope you'll have one for me at the end of the month :)
    • Admin
      Admin about 12 years
      @Slipp Douglas: Looks legit to me. The StartOnMount flag was added in 10.5 according to: mactech.com/articles/mactech/Vol.25/25.10/…
    • Admin
      Admin about 11 years
      A far more easier way would be to delete the /private/var/vm folder and to create a link to the volume where you want to store them. That's the way I am doing it.
    • Admin
      Admin about 11 years
      @LaurentCrivello: That's an intriguing idea, but are you sure it is really working? (see details in my note #1) dynamic_pager tends to silently fall back to using /private/var/vm if the target partition has not been mounted yet. I'm not 100% sure how symbolic links work under those conditions.
    • Admin
      Admin about 11 years
      @e.James: That's the way I do work since a week now and my disk space eissues fully disappeared. The swp file is going to the 2nd internal drive of my machine (not the startup partition), maybe that's the reason why it's mounted since the beginning...
    • Admin
      Admin about 11 years
      Cross reference to the opening poster's similar question in Ask Different: How can I move virtual memory swap files to a different drive or partition? (2010-09-12)
  • e.James
    e.James over 14 years
    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
    e.James over 14 years
    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.
  • Dave
    Dave over 14 years
    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.
  • e.James
    e.James over 14 years
    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
    e.James over 14 years
    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
    e.James over 14 years
    Brilliant! I used wait4path instead of the if/grep combination, and that cleans things up quite nicely. Thank you for the tip.
  • Admin
    Admin about 14 years
    Looks promising. Thank you for the link and detailed instructions!
  • e.James
    e.James about 14 years
    That's a valid criticism. I have no data to support my claims :)
  • Admin
    Admin about 14 years
    +1 Great stuff! I'm trying it out right now. Here's the link to the GoogleCode project: code.google.com/p/dynamicpagerwrapper
  • Admin
    Admin about 14 years
    make sure you're using at least revision 8 of the script: code.google.com/p/dynamicpagerwrapper/source/browse/trunk/…
  • e.James
    e.James almost 14 years
    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?
  • ekl
    ekl almost 14 years
    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
    ekl almost 14 years
    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!
  • e.James
    e.James almost 14 years
    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
    e.James over 13 years
    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.
  • Admin
    Admin about 12 years
  • Slipp D. Thompson
    Slipp D. Thompson about 9 years
    On newer OS Xes (10.10, but not 10.8, unsure about 10.9), com.apple.dynamic_pager.plist is in XML format in a stock installation— both the sudo plutil -convert … lines are unnecessary.