Region-based memory management

A lot of the memory management in Plash is done using regions.
Regions work like this:

You create a region. This allocates a medium-sized block (eg. 1k) initially.

You allocate blocks from the region.

You free the whole region. This frees all the blocks that were allocated from it.

Regions don't provide a way to free individual blocks in the region.
This means that allocation is fast, because there's no fragmentation
within a region. Deallocation is fast too, because all the blocks are
freed in one step.

The main reason for using regions in Plash is convenience.
Deallocation becomes much less of a burden, and is easier to get
right, so the chances of memory leaks are reduced. If a complex
structure is region-allocated, you don't need to traverse the
structure to free each node individually.

Using regions works well when allocation and deallocation follow the
structure of the function call tree: when a structure is not used
outside of the function that allocates it or the parent of the
function that allocates it. When this is not the case, and the
amounts of storage allocated are large, regions are not so good.

Plash uses reference counting for storage management when regions are
not appropriate.

It is possible to attach explicit finalisers to a region, so that when
the region is free, other resources are freed, eg. file descriptors
can be closed.