Copyright © 2004 Dave Bayer. Subject to the terms and conditions of the MIT License.
This page is www.math.columbia.edu/~ bayer/OSX/swapfile/Panther/
The solution given on this page does not work for OS X 10.4 (Tiger). A more recent version works for both Panther and Tiger.
OS X 10.4 (Tiger) solution: Moving the swapfile in Mac OS X 10.4 (Tiger)
In Panther, one can simply wait at the appropriate point in /etc/rc for the needed volume to mount. In Tiger, often no amount of waiting suffices; one needs to explicitly mount the needed volume. Finding the needed volume is tricky, because the only way to refer to a volume this early in the boot process is by its BSD name of the form /dev/disk1s10, but BSD names are not consistent across boots.
/dev/disk0s10 6280512 151776 6128736 2% /Volumes/Swapthen edit /etc/rc.swapfile to read
swapvolume=Swap
swapdir=/private/var/vm if [ -f /etc/rc.swapfile ]; then . /etc/rc.swapfile; fi # inserted locally
sudo defaults write /Library/Preferences/SystemConfiguration/autodiskmount AutomountDisksWithoutUserLogin -bool true
Moving the swapfile is the crux move, when installing a new release of OS X. There is a lot of partial, conflicting advice on the web concerning how to and whether to relocate the virtual memory swapfile to a separate partition. The speedup is debatable but significant and free; showing the machine who's boss is priceless. OS X is going to use a swapfile whether one moves it or not; a decision to move the swapfile has nothing to do with the question of how much memory to install.
If one tries to move the swapfile, there are various possible unintended outcomes:
This is a good first hack for Unix novices, but one should read everything written on the web about this topic with a healthy degree of skepticism, including everything written here. Only believe what you can confirm for yourself. Installations and permissions differ; upgraded systems don't behave like clean installs, and because this hack isn't supported by Apple, no one is sure of all the relevant variables. We're all trying to be helpful, but it is easy to make false inferences from a few trials on a few machines. The only sensible approach is to experiment with a clean install of OS X on a machine you can afford to mess up, and determine exactly how your system behaves under a series of experiments. Familiarize yourself with how your system behaves when it is working properly, so that you can tell the difference when it isn't working properly. Learn to write bits of code by imitation, after reading nearby existing code. Then choose a robust, safe, stress-tested method that you understand for moving the swapfile, move your swapfile, and move on. If it were easier than this, it wouldn't be called a hack.
A good resource for better understanding the Mac OS X boot process is System Startup, found in Mac OS X Documentation. The Bourne shell system-initialization scripts /etc/rc.boot and /etc/rc are run early in the boot process, but after the option to enter single-user mode. We shall be modifying /etc/rc; if imitation doesn't cut it for Bourne shell programming, go to original sources, and read Steve Bourne's Introduction to the Unix Shell.
See Advantages of Multi-Partition Drives for a discussion of the advantages of partitioning. Many believe that ideally, a swap partition should be on a separate and very fast drive. Others, such as laptop users like myself, find it more practical to put the swap partition on the boot drive. The fastest partition on a drive is the first, or outer partition. One should place either the system or swap here, and the other second, but this isn't mandatory. Once a partition fills to 85% of capacity, its performance seriously degrades, so leave room on the system partition for future growth. With developer tools and other third-party additions that must live with the system, my OSX partition contains nearly 6 GB of files. For a while I arranged my TiBook partitions Swap (3 GB), OSX (9 GB), OS9 (2 GB), User (41.4 GB), and I put users and any third-party applications that I can on User. This proved too tight for the OSX partition (Adobe products sometimes filled it with their cache files) so when I moved to an 80 GB internal drive after a drive failure, I increased OSX to 15 GB for good measure. If I'd had an on-the-fly repartitioning tool like VolumeWorks, I would have done this sooner.
To partition your boot drive, make several backups of any data on the drive, which will be erased. Boot off the first install disk for OS X, and choose Open Disk Utility... from the Installer menu. Set up each partition Mac OS Extended (Journaled), except for the swap partition which should be Mac OS Extended. These notes assume that you name your swap partition Swap. Do not use space characters in the name. You can reboot into OS 9 and rename the swap partition .Swap to get the Finder to hide it, but this isn't necessary. Instead, we will hide the swap directory .vm on Swap. This way, the swap partition doesn't have to be dedicated; we could be moving the swapfile simply because our boot volume got too full, and we're too lazy to repartition.
The version of Disk Utility that comes on the 10.3 install disk creates partitions 0.12 GB smaller than requested, so to obtain a partion of 3.0 GB ask for 3.12 GB, and so forth. Apple must have a good reason for this, but it is ok to boot instead from a 10.2 install disk for this one step, to avoid losing this disk space. Back in 10.3 Disk Utility, enable journaling for the other partitions, but leave it off for the swap partition.
A longstanding rule of thumb is to make the swap partition twice the size of physical memory. I remember the gas lights era when this meant 32 MB for a 16 MB Unix machine, and we watched math computations use this 32 MB that would have needed 1 GB if we hadn't compressed the program's internal data. Then as now, when a single process begins to page-thrash, it is very painful to watch. We walked away; no one has the patience to just sit there. The signature is different when several processes collectively need more than physical memory, but they each fit by themselves: Switching between processes is slower, but one can stand to be in front of the machine. The signature is different again for a memory leak. By definition the leaked memory is never used again, so the process merrily marks as used far more than physical memory with no noticeable performance hit, until swap runs out and the process goes splat.
The swap partition also makes a handy bootstrap partition. One can backup, repartition, install a minimum system on Swap, boot from this system to restore the other partitions, and then erase Swap and use it as a swap partition. This argues for a size of at least 1.5 GB, to fit a minimum system and restore software.
Alternatively, the Apple application Activity Monitor indicates for my system memory a VM size of variable size, often around 4-5 GB. A smaller swap partition than this will become the limiting factor for virtual memory. Use a swap partition which is larger than this size, if you can afford the disk space. A bit larger gives the file system room to turn around, but much larger is wasted.
The bottom line: If you need more than twice physical memory for your swap partition, you know who you are. People who say they need more swap than this probably have undiagnosed memory leaks, which are indeed being reported for 10.3.
To move a user, e.g. me, to a User partition, type into into the Terminal application
sudo ditto -v -rsrcFork /Users/me /Volumes/User/Users/meNow open the NetInfo Manager application and edit the user me to reflect this change:
home /Volumes/User/Users/meNow remove the original directory in Terminal:
cd /Users sudo rm -rf meYou may need to temporarily give another user administrative priviledges to finish moving the administrative user; I've had luck both ways. Leave /Users/Shared alone, Adobe Acrobat 6 for example won't install without it.
How does virtual memory work, out of the box? The system-initialization script /etc/rc contains the swapfile code
swapdir=/private/var/vm
if [ "${netboot}" = "1" ]; then
sh /etc/rc.netboot setup_vm ${swapdir}
fi
# Make sure the swapfile exists
if [ ! -d ${swapdir} ]; then
echo "Creating default swap directory"
mount -uw /
mkdir -p -m 755 ${swapdir}
chown root:wheel ${swapdir}
else
rm -rf ${swapdir}/swap*
fi
dynamic_pager -F ${swapdir}/swapfile
In principle, to move the swapfile, one simply redefines swapdir at the start of this code. The problem is that the partition Swap typically hasn't mounted yet.
To understand business as usual, type man df or man ls into the Terminal application, to understand the Unix commands we're about to use. The space bar moves forward through this documentation, and the Q key quits. Now type the display free disk space command
dfgetting a listing of the form
Filesystem 512-blocks Used Avail Capacity Mounted on /dev/disk0s12 18862272 12274896 6398760 66% / devfs 202 202 0 100% /dev fdesc 2 2 0 100% /dev <volfs> 1024 1024 0 100% /.vol /dev/disk0s10 6280512 151776 6128736 2% /Volumes/Swap /dev/disk0s14 4183488 1126792 3056696 27% /Volumes/OS9 /dev/disk0s16 86823312 50578912 36244400 58% /Volumes/User automount -nsl [380] 0 0 0 100% /Network automount -fstab [394] 0 0 0 100% /automount/Servers automount -static [394] 0 0 0 100% /automount/staticNote that the system's internal BSD name for my swap partition is /dev/disk0s10 and its Finder name is Swap; in all that follows, use instead of /dev/disk0s10 the internal BSD name of your swap partition and instead of Swap the Finder name of your swap partition.
Now type the list directory contents command
ls -l /Volumesgetting a directory listing of the form
drwxrwxrwx 18 root staff 612 5 Jan 14:29 OS9 lrwxr-xr-x 1 root admin 1 5 Jan 15:34 OSX -> / drwxr-xr-x 7 admin staff 238 5 Jan 15:34 Swap drwxrwxrwx 18 root staff 612 5 Jan 14:20 UserThis is where the system mounts volumes; they look like directories, and indeed the system can also put directories here, intentionally or as a result of swapfile code gone haywire. Now type
ls -l /private/var/vmgetting a directory listing of the form
drwx--x--x 8 root wheel 272 5 Jan 15:30 app_profile -rw------T 1 root wheel 67108864 5 Jan 15:34 swapfile0Note that the file swapfile0 was created at the time of the most recent boot, while the directory app_profile is older. app_profile maintains information about applications across boots, and probably shouldn't be moved unless your swapfile hack works all of the time; I choose never to move app_profile. However, swapfile0 is set up from scratch on every boot, and there is no harm in having different boots choose different locations, as long as obsolete files are deleted. Recognizing this is key to working out a graceful strategy for dealing with exceptional boots.
To edit /etc/rc, type into Terminal
cd /etc sudo cp rc rc.original sudo pico rcThis changes directories to /etc, and as superuser makes a backup copy of rc and edits rc using the pico command line editor. pico is a better choice than vi or emacs for casual users, because its directions are printed on the bottom; ^ stands for the Control key. vi is more powerful but has a steeper learning curve. emacs was abbreviated from "eight megabytes and constantly swapping" in an era when that was real money; a cat walking across an emacs keyboard could rearrange the orbits of the planets.
Alternatively, type into Terminal
sudo /Applications/TextEdit.app/Contents/MacOS/TextEdit /etc/rc &to edit as superuser with TextEdit, or install the demo or pay version of BBEdit and choose Open Hidden... from its File menu, showing All Files.
It is a good idea, however, to be able to use a command line editor in a pinch. If the /etc/rc file gets sufficiently messed up, the system may refuse to boot except in single-user mode. One chooses to boot in single-user mode by pressing the Command and S keys as the computer starts up; I have also been thrown into single-user mode after adding a single misplaced space character to /etc/rc. The computer screen is black with white text, and accepts any Unix command. If the root device is mounted read-only, follow the directions given on-screen before proceeding. One can run the pico command line editor, remove troublesome insertions from the /etc/rc or /etc/fstab files, and reboot normally.
How can one tell if Swap has mounted yet? Edit /etc/rc once, inserting the line
swapdir=/private/var/vm
if [ -f /etc/rc.swapfile ]; then . /etc/rc.swapfile; fi # inserted locally
if [ "${netboot}" = "1" ]; then
sh /etc/rc.netboot setup_vm ${swapdir}
fi
This insertion is harmless by itself, because the file rc.swapfile doesn't exist yet.
When the file rc.swapfile exists, this line executes the contents of rc.swapfile
exactly as if it were inserted here. Any typos in rc.swapfile will still derail the
startup process, throwing us into single-user mode, but we will be able to recover simply by renaming
rc.swapfile:
cd /etc mv rc.swapfile rc.swapfile.off reboot
Astronauts, pilots, and scuba divers practice emergency maneuvers until they become routine; you may want to try single-user mode now. Create a file /etc/rc.swapfile with contents
swapvolume = Swap
ConsoleMessage "swapvolume defined as ${swapvolume}"
and restart. There aren't supposed to be spaces around the equals sign,
so this will throw you into single-user mode. Recover.
To see console messages while booting, boot in verbose mode with the Command and V keys. The screen will look like single-user mode while these messages print.
Now, we can imitate the existing code that determines if the swapfile exists. Create a file /etc/rc.swapfile with contents
swapvolume=Swap
if [ -d /Volumes/${swapvolume} ]; then
ConsoleMessage "${swapvolume} available"
else
ConsoleMessage "${swapvolume} not available"
fi
and restart. This code prints a message to the system log file /var/log/system.log,
telling us whether or not /Volumes/Swap is present in the file
system at the time of the message. This code does not distinguish between a
mounted volume and a directory, an issue that will become significant later, but
doesn't matter now.
To read these messages after a system restart, type into Terminal
grep Swap /var/log/system.log | tailto see the last 10 lines of /var/log/system.log containing the word Swap. Confirm that Swap doesn't mount in time for the swapfile code of /etc/rc, by looking for lines of the form
Dec 23 16:37:59 localhost ConsoleMessage: Swap not availableRead from the bottom up, paying attention to times and recalling your last boot time.
A more cautious approach would have been to test rc.swapfile before restarting. To do so, add to rc.swapfile the lines
#!/bin/sh
swapvolume=Swap
if [ -d /Volumes/${swapvolume} ]; then
ConsoleMessage "${swapvolume} available"
else
ConsoleMessage "${swapvolume} not available"
fi
echo "rc.swapfile is finished"
In a terminal, change directories to the directory of your test version of rc.swapfile,
by typing cd and a space, dragging rc.swapfile from the Finder
into the terminal window to paste its path, backspacing over "/rc.swapfile", and pressing return. Now type
chmod +x rc.swapfile ./rc.swapfileand study the error messages. The ConsoleMessage command is unavailable, and will generate a message; we want to see the "rc.swapfile is finished" message. Any other messages are a cause for concern. This only tests part of our conditional logic; change the if to
if [ ! -d /Volumes/${swapvolume} ]; then
to toggle the logic and test again; remember to change it back. After testing, there is no harm in
leaving this extra code in place.
The simplest way to get Swap to mount in time after normal restarts is to add a line to the system file /etc/fstab:
# fs_spec fs_file fs_vfstype fs_mntops # # UUID=DF000C7E-AE0C-3B15-B730-DFD2EF15CB91 /export ufs ro # UUID=FAB060E9-79F7-33FF-BE85-E1D3ABD3EDEA none hfs rw,noauto # LABEL=This\040Is\040The\040Volume\040Name none msdos ro /dev/disk0s10 /Volumes/Swap hfs rw 1 2Be sure to replace the BSD name /dev/disk0s10 with the BSD name that corresponds to your swap partition.
There is a flaw, however, with this modification to /etc/fstab: BSD names are created at boot time, and are not guaranteed to be consistent across boots. In practice, it appears that the partitions on the boot device get numbered consistently, but other devices get numbered in the order that they spin up. However, even this is not documented as certain. See the discussion Topic: drive numbering inconsistent /dev/diskXs10 ?.
There are other, more stable ways of referencing Swap:
UUID=AC05CEB8-906A-3AB1-BD04-D0FC29B9C384 /Volumes/Swap hfs rw 1 2 LABEL=Swap /Volumes/Swap hfs rw 1 2Unfortunately, these are only understood by autodiskmount, and do not appear to help us here. I could sometimes get these forms to work, but never to any advantage for our purposes.
My preferred approach is patience: If Swap hasn't mounted in time, wait a few seconds. Do not modify /etc/fstab. Instead, try a more elaborate version of /etc/rc.swapfile:
swapvolume=Swap
if [ ! -d /Volumes/${swapvolume} ]; then
swapcount=1
ConsoleMessage "Waiting for ${swapvolume} to mount"
while [ "$swapcount" -le 30 ]; do
sleep 1
if [ -d /Volumes/${swapvolume} ]; then
ConsoleMessage "${swapvolume} mounted after $swapcount seconds"
break
fi
swapcount=`expr $swapcount + 1`
done
fi
if [ -d /Volumes/${swapvolume} ]; then
ConsoleMessage "${swapvolume} available"
else
ConsoleMessage "${swapvolume} not available"
fi
Observe now that if Swap is a partition on the boot drive or on an IDE drive, then it mounts within a few seconds. Otherwise, Swap fails to mount. It turns out that in OS X 10.3, these drives don't mount until a user logs in. See 10.3: A fix for local drives not mounting until user login The fix is to type into a terminal
sudo defaults write /Library/Preferences/SystemConfiguration/autodiskmount AutomountDisksWithoutUserLogin -bool true
Now confirm that Swap mounts in time for the swapfile code of /etc/rc. Stress-test this mechanism: Log out all users, wait for the system to quiet down, and perform a forced reboot by pressing the Control, Command, and Power keys. Note that Swap still mounts in time after forced reboots.
A forced reboot is an emergency procedure; OS X is a swarming anthill of background processes, all of which get killed without ceremony by a forced reboot. The system can end up in an unstable state, turning your hacking session into a recovery session. It is essential to log out all users before testing forced reboots; in particular, anyone logged in and using FileVault could get hosed. There seems to be no completely safe protocol for testing forced reboots; the same key combination while asleep simply wakes the computer, and a forced reboot in single-user mode appears to skip the extra checks. Apparently, if we know the boot is safe, the system also knows the boot is safe.
It is important to have sorted out how to mount the swap partition before trying to move the swapfile, because moving the swapfile during these experiments can make a mess that is difficult to clean up. If you tell the system to use /Volumes/Swap before it mounts, it creates and uses a directory by the same name, and later, Swap mounts as /Volumes/Swap 1. This is a truly famous mishap for swapfile adventurers. From now on, the directory Swap passes the test to see if Swap has mounted. One way to dig out of this hole is to rename the Swap partition, comment out every reference to Swap, and reboot, so that Swap becomes an unused directory that can be deleted. However, if this fix goes poorly, you only compound the problem. It is better never to make this mistake in the first place.
For this reason, a safer test is
if [ -d /Volumes/Swap/.Trashes ]; thenbecause the invisible .Trashes directory exists on volumes, but not typically in other directories.
Warning: Various people have dramatically sped up their boot times by patching the behavior of BootCacheControl, as described in Topic: HOWTO: Slow 10.3.2 startup fix. I now recommend against this modification. I traced a problem to this fix, where my restarts were hanging indefinitely at the "Login Window Starting" prompt. I'm guessing my boot cache got out of sync. This makes sense; a cache out of sync can wreak all manner of havoc. Apple couldn't get it working, took it out, others discovered they could put it back in, it usually works... Know the song? To remove this fix, type
sudo rm /usr/sbin/BootCacheControl
We are now ready to try a patient, conservative strategy: Leave app_profile alone. Move the swapfile if we can, but check first to see if we can, and do something reasonable no matter what happens. Replace the contents of /etc/rc.swapfile with the code
##
# After the line in the system startup script /etc/rc
#
# swapdir=/private/var/vm
#
# insert the line
#
# if [ -f /etc/rc.swapfile ]; then . /etc/rc.swapfile; fi # inserted locally
##
swapvolume=Swap
if [ ! -d /Volumes/${swapvolume}/.Trashes ]; then
swapcount=1
ConsoleMessage "Waiting for ${swapvolume} to mount"
while [ "$swapcount" -le 30 ]; do
sleep 1
if [ -d /Volumes/${swapvolume}/.Trashes ]; then
ConsoleMessage "${swapvolume} mounted after $swapcount seconds"
break
fi
swapcount=`expr $swapcount + 1`
done
fi
if [ -d /Volumes/${swapvolume}/.Trashes ]; then
ConsoleMessage "Using ${swapvolume} for swapfile"
if [ -f ${swapdir}/swapfile0 ]; then
rm -rf ${swapdir}/swap*
fi
swapdir=/Volumes/${swapvolume}/.vm
else
ConsoleMessage "Unable to use ${swapvolume} for swapfile"
fi
Test this code under a variety of conditions.
This code has been groomed by various people, and has the following virtues:
If you can pick any more fleas off this code, however obscure, let me know. It is intentionally intolerant of spaces in the name of the swap partition, because the code in /etc/rc is similarly intolerant. One could instead define a symbolic link, to permit spaces without further modifying /etc/rc, but it is simpler to not use spaces. Simple is good.
If your swap partition is on your boot drive, you can probably get away with shaving a few seconds off each normal restart by also modifying /etc/fstab, using a BSD name like /dev/disk0s10. To me, this slight speedup doesn't seem worth the potential risk.
Further testing establishes that Swap is nearly always mounted by the end of /etc/rc, after the SystemStarter call:
SystemStarter -gr ${VerboseFlag} ${SafeBoot}
exit 0
This is also true after forced reboots. Others have had success with simply
redefining swapdir, and moving the existing swapfile code in
/etc/rc to just before the
exit line. However, SystemStarter calls a plethora of startup
scripts, all of which would then run without benefit of virtual memory. I cannot
see any harm in this, but as a mathematician I've learned that a lack of
imagination is not a proof of anything.
An alternative proposed by ptwithy on Mac OS X Hints, is extremely amusing: Insert instead into /etc/fstab
/dev/disk0s10 /private/var/vm hfs rw 1 2This has the distinct advantage of avoiding any need to edit /etc/rc; it mounts Swap where /etc/rc already wants to put the swapfile. There are compelling arguments for not modifying "Apple-owned" system files such as /etc/rc; one is that Apple may overwrite your mods without warning on any future system update. The disadvantage to this method is that it doesn't address the issues raised by forced reboots. It can waste space on the root volume: After a forced reboot, Swap is instead mounted as /Volumes/Swap, and the swapfile is placed in the directory /private/var/vm. After the next normal restart, all is well again, but the directory /private/var/vm is inaccessible, having been replaced in the directory tree by the volume /private/var/vm, and its obsolete swap files hang around unerased, choking the root volume. Also, this strategy effectively maintains two versions of app_profile, one for forced boots. It also runs into the BSD name issue; I could not get the alternative /etc/fstab forms to work here.
There are various automated solutions out there for moving the swapfile. I prefer to carefully understand all modifications to my system, so that I can debug problems. However, the vast majority of people who move their swapfile are going to rely on an automated solution they don't understand. If you've understood this far, you share a responsibility to the community to go pick a current automated solution and dissect it, and give the author feedback. In my experience, the authors of these programs are extremely responsive. In addition, if you see a "just use this program, it worked fine for me" post on the web, where the author of the post gives no clue that they examined the changes to their system, consider posting a followup with your analysis. Without such followups, all anyone can safely assume is that the test system didn't curl blue smoke.
One example of an automated solution that provides beta support for OS X 10.3 behaves as follows, as of January 9, 2004: It presents a slick, confidence-inspiring user interface. (One shouldn't draw conclusions from this; the Cocoa framework makes this easier than any non-programmer would believe possible.) After the user selects the swap volume, it makes a backup copy of /etc/rc, and make the following changes to /etc/rc: It replaces the line
swapdir=/private/var/vmwith the lines
/sbin/autodiskmount sleep 3 swapdir=/Volumes/Swap/vmand it replaces the line
appprofiledir=/private/var/vm/app_profilewith the line
appprofiledir=/Volumes/Swap/vm/app_profile
In testing, this worked for me, once after a normal restart and once after a forced reboot. However, no option is provided to change the autodiskmount defaults for non-IDE drives, so they could pose a problem. In my experience, the call to autodiskmount is harmless, but has no appreciable effect on waiting times; the volumes that are going to mount are already about to mount. Waiting 3 seconds usually suffices, but I've experienced delays of up to 11 seconds, hence my preference for a conditional loop. There is also no conditional code to notice if Swap fails to mount, so this method could make one of the classic mounting messes in /Volume, with no provision for cleaning it up.
Thanks to Adam, Rolf, and Kenneth "TigerKR" Roberts for helpful comments. Kenneth's help was crucial in flagging the BSD name issue, finding the workaround for non-IDE drives, and grooming the /etc/rc insertion.
All comments are welcome. I've moved my swapfile in every version of OS X, and I'm just getting the hang of it. I long ago lost track of my original sources. For the new ideas needed for 10.3, I started by reading 10.3: Move swap to another partition in Panther and the comments that follow.