Garbage collector

A persistent system such as Gracle must have a good memory-management system. Objects of all kinds of sizes will be allocated in its single address space, and those objects will be linked in complex ways, forming a general graph. The entire address space cannot be garbage collected while having application processes waiting, as this would introduce very long pauses, perhaps hours, given that the address space is considerably larger than physical memory, and that garbage collection will thus involve paging to and from very slow disk memory.

Our current thinking is to have two main generations of memory, where the second one can be further subdivided as necessary.

The nursery is a small-ish per-thread (1Mbyte or so) memory that is managed entirely by the thread itself. The small size means that the entire nursery can be collected in a millisecond or so, which is acceptable for most multi-media applications. We are thinking of using a sliding collector in order to have a very precise idea of the age of an object in the nursery.

The older generations are managed by an incremental garbage collector that runs in its own thread(s). Objects allocated here are never moved, which simplifies hashing, I/O (DMA), FFI code, etc.

Very large objects are directly allocated in the older generations.

There are no pointers from objects in the older generations to any nursery, nor are there any pointers from objects in one nursery to objects in another nursery. Any attempt to store a pointer from an object in the older generations to an object in some nursery, will automatically trigger the promotion of the nursery object and of all the objects in its transitive closure. This reflects the (not necessarily true) assumption that an object pointed to by an object that has survived for a long time, will itself survive for a long time.

Each new Gracle (light-weight) process is given a stack of a reasonable size (say a few Mbytes) in the global address space. The last page is unmapped so that stack overflows can be detected effectively and efficiently. The compiler must take care to generate code that must not skip an entire page (allocating more than 4kbytes of local variables for instance) without also generating code to try to touch that page.