note: copied from SuperUser:
For older versions of OSX, see this thread on forums.macosxhints.com.
Credit goes to dblu for explaining the use of plutil
, ZILjr for introducing the wait4path
command, and ekl for simplifying 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 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/ &&
/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.
Exclude the path from Time Machine
In OS X 10.7 and later you can do this with tmutil. Example:
sudo tmutil addexclusion -p /Volumes/Swap/.vm
For that example, to review the result:
tmutil isexcluded /Volumes/Swap && tmutil isexcluded /Volumes/Swap/.vm
If the volume used for swap need not be indexed
Use mdutil. Example, to switch off then erase the store:
sudo mdutil -i off /Volumes/Swap && sudo mdutil -E /Volumes/Swap
What you're seeing is normal, and desired behavior.
OS X, like Linux and BSD, has a disk cache. This means anything read from or written to disk is kept in memory. The "Inactive" memory includes this disk cache.
This answer on AskDifferent explains it, as does this post on macosxhints.com:
However, X's underpinnings (ie the UN*X kernel) provide both these
features without any inputs being needed by the user. It's called the
file system buffer cache. The one most significant difference is that
the size of this buffer cache is dynamic. It starts of with some small
size and can grow and shrink as the i/o demands and Apps memory
requirements vary over time.
It's called a 'buffer cache' because it buffers the i/o data on its
way to/from the disk. When an App writes data it first will be
deposited into the Apps file buffer memory region and will
subsequently be requested via library routines to have the kernel (the
OS) copy it from the App's buffer to disk. The kernel will oblige and
will copy it first to its buffer -- the file system buffer cache. If
the kernel requires more room in its buffer cache it will obtain it
from the free memory. When this happens the free memory value, in say
the Terminal's top command, will immediately show a reduction of free
memory. At some later point the kernel will copy this data (referred
to has dirty buffers) to the appropriate disk location. I believe the
frequency of this being done is 30 secs -- called sync-ing to disk.
Note that having memory paged out to disk is not always a bad thing. If memory pages are completely inactive, paging them out to disk can improve performance, because they are wasting RAM which could otherwise be used for disk cache. Once they are paged out and you stop watching movies, when needed they will be paged back in, automatically replacing the buffers and disk cache. You don't need to run purge
each time. Just let OS X manage the disk cache as it was designed to do.
For more information on this, consult the wikipedia article on paging, and the article on the Page cache.
TL;DR information:
Here's an article describing how swap works under Linux. WHile not 100% applicable to OS X, the concept is the same. I'll quote the relevant part:
When an application needs memory and all the RAM is fully occupied,
the kernel has two ways to free some memory at its disposal: it can
either reduce the disk cache in the RAM by eliminating the oldest data
or it may swap some less used portions (pages) of programs out to the
swap partition on disk. It is not easy to predict which method would
be more efficient. The kernel makes a choice by roughly guessing the
effectiveness of the two methods at a given instant, based on the
recent history of activity
Since you're watching a DVD or a movie, the most recently active pages of memory are the disk cache, so OS X decides to keep that in RAM and swap out pages of memory which have been inactive from before you started accessing the video files. Once you stop accessing video files and access the programs using the memory pages which were swapped out, the reverse is true: OS X will discard the disk cache containing the video data and replace it with the memory pages which it swapped out. Then your swap usage will decrease.
Here's a bit more information, specific to FreeBSD (which is similar to Mac OS X):
FreeBSD will use 'all of memory' for the disk cache. What this means
is that the 'free' bucket typically contains only a few pages in it.
If the system runs out, it can free up more pages from the cache
bucket.
System activity works like this: When a program actively references a
page in a file on the disk (etc...) the page is brought into the
buffer cache via a physical I/O operation. It typically goes into the
'active' bucket. If a program stops referencing the page, the page
slowly migrates down into the inactive or cache buckets (depending on
whether it is dirty or not). Dirty pages are slowly 'cleaned' by
writing them to their backing store and moved from inactive to cache,
and cache pages are freed as necessary to maintain a minimum number of
truely free pages in the free bucket. These pages can still be
'cleaned' by allocating swap as their backing store, allowing them to
migrate through the buckets and eventually be reused.
[...]
The VM buffer cache caches everything the underlying storage so, for
example, it will not only cache the data blocks associated with a file
but it will cache the inode blocks and bitmap blocks as well. Most
filesystem operations thus go very fast even for tripple-indirect
block lookups and such
[...]
FreeBSD has arguably some of the best swap code in existance. I
personally like it better then Linux's. Linux is lighter on swap, but
doesn't balance system memory resource utilization well under varying
load conditions. FreeBSD does.
FreeBSD notes the uselessness of existing pages in memory, and decides
that it might be advantageous to free memory (enabled by pushing pages
to swap), so that it can be used for more active purposes (such as
file buffering, or more program space.) It is a terrible waste to
keep unused pages around, for the notion of saving (cheap) disk
space. Since low level SWAP I/O can be faster, with less CPU overhead
than file I/O, it is likely desireable to push such unused pages out
so that they can be freed for use by higher overhead mechanisms.
(note 1)
(Emphasis mine, check that bolded part for specifically what you're asking about, that is, "Why is swap being used when I have inactive memory?)
Best Answer
AFAIK the reason all those swap files were created so quickly in Safe Mode is because dynamic_pager fell back to an initial swap size of 64MB. How many swap files did you see? How many do you want to see? How many are you seeing?
Right now on my Mac Pro (desktop) running OS 10.8.3 I have 7 swap files (numbered 0-6). Is that what you want? Actually, since you've pointed this out, I'm going to try to reduce that to 2.
If you really want to create a lot of swap files, just set
-S 67108864
BTW, 1073741824 = 2^30 = 1 GiB
Followup
Turns out there is a bug in
dynamic_pager
(at least under Mountain Lion 10.8.4) where setting-S 2147483648
(= 2 GiB) fails because of some sort of 32-bit conversion error.2147483648 as a 32 bit signed in is actually -2147483648 or 0x80000000 which gets extended to a 64 bit number by extending the MSB and turned into 0xFFFFFFFF80000000 which is then converted to a 64 bit unsigned which is 18446744071562067968 or 2 GiB * 8 GiB. Crazy. So after you mess with the dynamic pager options, look for error messages in the console logs.