the lost malloc()
33 points by spc476
33 points by spc476
This was a good read! I love finding code from before K&R C, when the augmented-assignment operators were flipped (=+ instead of +=)
these malloc() and mfree() work on explicit memory regions! ... You could deallocate all its memory resources by just discarding the entire region you delegated to it.
This idea of a zone allocator keeps coming back. I've always wondered why it wasn't more popular in web servers, where it'd be natural to just bulk-free all memory after an HTTP request is done. I spent so much time tuning garbage collection in Java webapp servers and it was tempting to think it could all be trivialized.
Note that this article doesn’t make it very clear that dmr/malloc is the kernel allocator; I think all the others it discusses are userland allocators. (The early unix kernels had their source split between directories ken and dmr, a kind of charming instance of Conway’s law.)
(I’m mildly disappointed the article omitted the notoriously cursed Bourne shell allocator.)
I've always wondered why it wasn't more popular in web servers, where it'd be natural to just bulk-free all memory after an HTTP request is done.
Both Apache httpd and nginx work that way; it’s a common idiom in C network servers. (previously)
Pool allocators get a lot of their efficiency from type punning so they are hard to write in languages other than C. In C++ you have added friction from placement new, the need to explicitly bless the type of a fresh allocation, and keeping track of which objects have destructors that must be called. You can write homogeneous pool allocators in higher-level languages with an array per type (and they can be useful to control GC pressure in languages like Java) but then the per-request top level needs to know every type that might be allocated, and there are multiple pools to reset instead of just one.
The other problem they have is (in languages that have manual memory management) you need to know none of your pointers have escaped. Any globally accessible cache must only ever hold data that is outside of the per request pool.
I’ve seen per request pools suggested on multiple projects as a way to remove deallocation overhead and possible leaks, and it has always turned out those leaks were more complex than just a missing free.
I think the lack of arenas is (in part) a combination of two things. First, most versions of Research Unix had small memories (everything through V7 mostly ran on the PDP-11 series, with 64KB of data address space per program), which increases the practical impact of the overhead and wastage from arenas. Second, even through V8 there was no mmap(), so program data space was fundamentally linear (with a top, the break). Even if you had layered an arena allocator on top of it, you'd need an underlying malloc-like block allocator to carve up and release the arena areas; in effect they'd be an additional layer on top of malloc() and free().