How I debugged the es garbage collector

From: Paul Haahr <haahr@netcom.com>
Newsgroups: comp.lang.scheme
Subject: Re: _Really_ tiny Scheme anywhere?
Date: 21 Jul 1994 02:27:48 GMT
Message-ID: <HAAHR.94Jul20192750@netcom9.netcom.com>

Bill Sommerfeld  wrote
> Given that many UNIX systems these days seem to support mmap() and
> munmap(), it occurs to me that it might be worthwhile to unmap the old
> space after you're done cleaning it out, and then re-map a fresh new
> space, which will initialized with zeros on demand, on the next GC.
> The systems I'm familiar with either support mmap'ing "/dev/zero", or
> implement a MAP_ANONYMOUS flag.
> ...
> If (because of a GC bug) you accidentally reference something in 
> old-space after the GC completes, you'll find out immediately when the
> system gives you a memory access fault, rather than some time later on
> when it's harder to figure out what happened..
I implemented something like this for the GCPROTECT mode of es, a unix shell with scheme-like semantics that Byron Rakitzis and I wrote.

If the collector was compiled with GCPROTECT off, it acted as a traditional, non-conservative two-space collector. With GCPROTECT on, ten spaces rather than two were used, and all but the current ``new space'' were marked invalid -- that is, any access would trigger a segmentation violation.

I had expected this to lead to horrible performance. In fact, the performance impact was so negligible, that I always ran with GCPROTECT on, at least on the platforms which I could figure out how to make mmap do what I wanted it to.

The reason that ten spaces were used instead of two was so that even the stalest of pointers would trigger a core dump. Under normal mode of operation, this probably was not an issue, but for debugging the garbage collector itself -- in particular, for making sure that all of the rootset was identified for the gc -- there is an even more drastic mode, GCALWAYS, where having ten spaces as opposed to two made a difference.

With GCALWAYS on, every allocation that might initiate a collection does. GCPROTECT and GCALWAYS, run in combination, made it trivial to track down almost all of what had previously been the hardest type of bug in the program to find.

As to performance of mapping memory, with both GCALWAYS and GCPROTECT on, es was still able to do several thousand allocations a second on my 68040 NeXT machine, leaving me no concern about the speed of mmaping.

I strongly recommend this technique to anyone implementing a similar collector. The code in es is in the public domain, but reasonably entangled with the rest of the system.

Paul Haahr