Mac OS X … “fork: Resource temporarily unavailable”

Almost a year ago, I made the switch to using Mac OS X as my primary workstation.  As difficult as the transition was during my first 3 weeks, it has now become second nature to me.  I haven’t had any major issues along the way, but now and then, I have had to tweak a thing or two.  Here is the most recent such example.

Lately, I’ve been seeing a fair number of the following error, when launching commands under Bash within a local Terminal session.  It’s rather annoying, because it stops me from getting any work done.  As a systems administrator, I have lots of Terminal sessions open, and this is where the error has always manifested itself.

[laptop:~ root]$ ssh somehost

-bash: fork: Resource temporarily unavailable

The first time this happened to me, I didn’t think much of it, so I rebooted my system.  Today, I did not feel like rebooting my system, because I have a ton of work in progress.  I suspect most people won’t hit this resource limit, but if you’re a power user, you eventually might.

Like other Unix-like operating systems, Max OS X limits the maximum number of processes, system-wide and per-user, but it does so with a rather conservative number.  On my Mac, system-wide processes were limited to 512, and per-user processes were limited to 266.  I’ve never encountered this problem on Linux, because these values are dynamically set in the kernel, based on the amount of memory installed in the Linux system.

Here’s how I resolved this problem.

  • First, determine what your system’s current limits are.  These are the values on my installation of Mac OS X 10.5 with 4 GB of RAM.
[laptop:~ root]$ sysctl -a | grep maxproc | grep =

kern.maxproc = 512
kern.maxprocperuid = 266
  • Now set these to higher values.  I suggest approximately doubling what you already have.
[laptop:~ root]$ sysctl -w kern.maxproc=1024
[laptop:~ root]$ sysctl -w kern.maxprocperuid=512
  • You’ll also want to apply these changes automatically at system bootup.  To do so, add them to the /etc/sysctl.conf file.
[laptop:~ root]$ sudo vi /etc/launchd.conf
[laptop:~ root]$ cat /etc/sysctl.conf

kern.maxproc=1024
kern.maxprocperuid=512
  • At this point, launched processes will still inherit the default maxprocperuid value of 266.  I would like to change this inherited default value for new processes automatically, but I haven’t found a way to increase the default system-wide soft-limit of maxprocperuid on Mac.  On Linux, I simply update the /etc/security/limits.conf file, but I don’t see such a file under Mac OS X.  If you know of a way to do this in Mac OS X, leave a comment below.  For now, I’ve added the following command to my user’s .bash_profile file.  The value of 512 is intended to match that of kern.maxprocperuid shown above.
ulimit -u 512
  • To confirm the change, launch a new Terminal session, and run the following command.  Before the change, you will have seen “266.”  After the change, you should see “512”.
[laptop:~ root]$ ulimit -a

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) 6144
file size               (blocks, -f) unlimited
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 256
pipe size            (512 bytes, -p) 1
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 512
virtual memory          (kbytes, -v) unlimited

A commenter posted a link below, referring me to a method of changing the default system-wide values at boot time.  I’ve elaborated in greater detail below.

My system is running a newer version of Mac OS X (10.5.8), and it uses a launchd daemon, which is the parent of all processes (similar to init under Linux).  This launchd daemon can read options from a configuration file, which can be used to set the various “limit” values.  There is both a system-wide and a per-user launchd daemon, and each can be configured independently, although the user’s launchd daemon will inherit its values from the system’s launchd at boot time .  The system-wide daemon values will always limit the maximum values that a per-user daemon can set.

Further, the launchd daemon can be re-configured live (with certain limitations), using the launchctl command, without requiring a reboot.  Though, I suggest that you add your custom settings to /etc/launchd.conf to persist your changes across reboots.

  • First, check your existing user’s launchd settings.  For each setting, there are two values.  A “soft” limit on the left, and a “hard” limit on the right.  The soft limit is the currently active limit.  However, you can increase the soft limit up to (but not greater than) the hard limit.  The root user can increase the hard limits of the system-wide launchd, without a reboot.  However, you cannot change a user’s launchd hard limits without a reboot (even if trying to do so as the root user).
[laptop:~ user]$ launchctl limit

         cpu         unlimited      unlimited
         filesize    unlimited      unlimited
         data        6291456        unlimited
         stack       8388608        67104768
         core        0              unlimited
         rss         unlimited      unlimited
         memlock     unlimited      unlimited
         maxproc     266            532
         maxfiles    256            unlimited
  • Next, check your system-wide setings.  Notice how the user-specific values are identical to the system-wide settings, as they were inherited at boot time.
[laptop:~ user]$ sudo su -
[laptop:~ root]$ launchctl limit

         cpu         unlimited      unlimited
         filesize    unlimited      unlimited
         data        6291456        unlimited
         stack       8388608        67104768
         core        0              unlimited
         rss         unlimited      unlimited
         memlock     unlimited      unlimited
         maxproc     266            532
         maxfiles    256            unlimited

[laptop:~ root]$ exit
  • If you do not need to increase the user-specific values before rebooting, then go on to the next step.  Otherwise, if you need to resolve your immediate “fork: Resource temporarily unavailable” problem, try the following steps.  (You may need to close some applications first.)  Remember, you will not be able to increase the soft values higher than the hard limit imposed by the user’s launchd daemon.  If you try to set the soft limit too high, the value will be reduced to the hard limit value.  As illustrated in the example below, increasing the maxproc soft limit to 512 succeeds, while increasing the maxproc hard limit to 1024 fails.  Run the following commands as the user (not root).
[laptop:~ user]$ launchctl limit maxproc   512 1024
[laptop:~ user]$ launchctl limit maxfiles  512 unlimited
[laptop:~ user]$ launchctl limit

         cpu         unlimited      unlimited
         filesize    unlimited      unlimited
         data        6291456        unlimited
         stack       8388608        67104768
         core        0              unlimited
         rss         unlimited      unlimited
         memlock     unlimited      unlimited
         maxproc     512            532
         maxfiles    512            unlimited
  • Now, place new system-wide default settings into the /etc/launchd.conf file.  You will need to create this file, as it does not exist by default.  This file contains only the options that are passed to launchctl (not the launchctl command itself).  Note that on OS X 10.5.8, the maxproc value has a maximum hard limit of 2500.
[laptop:~ user]$ sudo vi /etc/launchd.conf
[laptop:~ user]$ cat /etc/launchd.conf

limit maxproc 1024 2048
limit maxfiles 1024 unlimited
  • You may also create a configuration file at $HOME/.launchd.conf, which can be used to set the per-user values.  But you need this only if you want smaller default values than what the system allows the user-specific launchd to inherit.

For additional information on launchctl settings, check out the following man pages.

[laptop:~ user]$ man launchd.conf
[laptop:~ user]$ man launchctl
[laptop:~ user]$ man getrlimit