ten thousand small processes

Chuck Swiger cswiger at mac.com
Sat Jun 21 23:45:10 PDT 2003

D. J. Bernstein wrote:
[ ... ]
> I don't care much about the 3-page text segment. But I do care about the
> 39 extra pages of VM, and the 8 extra pages of DRAM. There's no obstacle
> to having a small program fit into _one_ page per process; two or three
> can be excused, but 39 is absurd. (Yes, I know that Solaris is worse.)

Indeed-- Solaris insists that all programs be dynamicly linked; Sun claims that
staticly linked programs violate the SPARC ABI.

[ ... ]
> Why doesn't the compiler automatically merge some bss into data when
> that saves a page?

Most executable object formats seem to prefer to page-align different sections, 
in VM if not on disk.  I don't know ELF well enough to know whether there is an 
equivalent to the following from /usr/include/mach-o/loader.h, used by NEXTSTEP 
and MacOS X:

  * The file type MH_OBJECT is a compact format intended as output of the
  * assembler and input (and possibly output) of the link editor (the .o
  * format).  All sections are in one unnamed segment with no segment padding.
  * This format is used as an executable format when the file is so small the
  * segment padding greatly increases its size.

...but this did (or used to do) the right thing with regard to merging data and 
bss onto a single page.

> Why can't I omit exit(), manually or automatically, when it's unreachable?

There's a Usenet thread around the following message-ID:


...which might be interesting:

]In comp.sys.sun.misc Casper H.S. Dik <Casper.Dik at sun.com> wrote:
]> "Chuck Swiger" <chuck at codefab.com> writes:
]>> Under Solaris, /bin/true and /bin/false are shell scripts rather than binary
]>> executables, but a minimal assembly implementation of these two programs
]>> would not need to perform any system calls or invoke any library routines at
]>> all, no?
]> _exit()?
]A point.
]On the other hand, valid one-line C implementations-- int main() { return 0;
]}-- do not explicitly call exit() or _exit().  They simply return from
]subroutine to a system-provided stub, once called /lib/crt0.o, which was the
]thing that passed control to _main() in the first place.
]If Solaris will insist that one dynamicly links crt0.o to have the standard
]system _exit() symbol available, okay.  However, nothing in the code above
]requires dynamic linking on systems which provide a static version of _exit.

> Furthermore, malloc() appears to chew up a whole new page of DRAM for
> each allocation, plus another page---is this counted in VSZ?---for an
> anonymous mmap.  Would it really be that difficult to fit 1076 bytes of
> requested memory into the 3000-odd bytes available at the end of bss?

Of course not, at least if you knew at compile time that one could use the 
equivalent of static arrays, rather than getting memory from a malloc() 
implementation.  For that matter, if you insist upon using dynamic allocation 
and getting memory at runtime, I suspect that using alloca() would be a win.

Hmm, yes:

chuck   9426  0.0  0.0   168   44  p0  S+    2:28AM   0:00.00 foo
chuck   9430  0.0  0.0   144   28  p0  S+    2:28AM   0:00.00 foo2

> I sure hope that there's some better explanation for the remaining 32
> pages than ``Well, we decided to allocate 131072 bytes of memory for the
> stack,'' especially when I'm hard-limiting the stack to 4K before exec.

The malloc manpage has some information that may be relevant:

      <       Reduce the size of the cache by a factor of two.  The default
              cache size is 16 pages.  This option can be specified multiple
[ ... ]
      To set a systemwide reduction of cache size, and to dump core whenever a
      problem occurs:

            ln -s 'A<' /etc/malloc.conf

...only, setting this option doesn't seem to make any difference to the memory 

183-sec% truss foo
readlink("/etc/malloc.conf","<<",63)             = 2 (0x2)
mmap(0x0,4096,0x3,0x1002,-1,0x0)                 = 671395840 (0x2804b000)
break(0x804d000)                                 = 0 (0x0)
break(0x804e000)                                 = 0 (0x0)
break(0x804f000)                                 = 0 (0x0)
break(0x8050000)                                 = 0 (0x0)
break(0x8051000)                                 = 0 (0x0)
nanosleep(0xbfbffa68,0xbfbffa60)                 = 0 (0x0)
exit(0x0)                                       process exit, rval = 0

...nor does setting the malloc flags to ">>" increase the VM usage.  But a truss 
of foo2, using alloca() versus malloc(), shows that we don't get a PAGEZERO 
section mmap'ed in (!), and we don't invoke brk() to grow the malloc arena:

189-sec% truss foo2
nanosleep(0xbfbff618,0xbfbff610)                 = 0 (0x0)
exit(0x0)                                       process exit, rval = 0


More information about the freebsd-performance mailing list