mem: heap allocator#8
Merged
Merged
Conversation
Implements a reasonably simple heap allocator. Small (less than ~2KB) allocations are rounded up to a fixed size bucket. These allocations are satisfied from 4KB pages of memory which is chunked by this bucket size. These chunks are linked, using an intrusive pointer in the chunk itself, to form a free list. In addition to the granular free list inside a span, the heap stores spans themselves in a free list. On initialization, it asks the OS for 64KB of memory, splits it into 4KB spans, and links them. When a bucket doesn't have any more memory to serve a request, it claims a span. When a span becomes empty, it is returned to the free list. It is not eagerly returned to the OS; only when the heap itself is destroyed. This means that the footprint of the heap is equal to its high watermark. In return for this tradeoff, the allocator's overhead is strictly a function of (a) this watermark at any given time and (b) the number of allocations and their sizes. Compare this to malloc(), in which the *order* of allocation also gives different fragmentation patterns. I also added some small things: - I pulled in a small fork of ubench.h that I've been working on, which is not in a releasable state but is usable - I ported the existing sp_glob.h benchmark - I wrote some benchmarks for the heap allocator to ballpark it against glibc, but ended up not using the framework - I wrote a small table renderer for the benchmarks - WIP: I moved the existing hash table benchmark to WIP - Unrelated: removed SP_MEM_ARENA_BLOCK_SIZE - Unrelated: reordered the mem section of the header so that the docs for the heap allocator (and by extension other structs) could be colocated with its and only its header - Remove: sp_mem_os_alloc_zero(), vestigial
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements a reasonably simple heap allocator. Small (less than ~2KB) allocations are rounded up to a fixed size bucket. These allocations are satisfied from 4KB pages of memory which is chunked by this bucket size. These chunks are linked, using an intrusive pointer in the chunk itself, to form a free list.
In addition to the granular free list inside a span, the heap stores spans themselves in a free list. On initialization, it asks the OS for 64KB of memory, splits it into 4KB spans, and links them. When a bucket doesn't have any more memory to serve a request, it claims a span.
When a span becomes empty, it is returned to the free list. It is not eagerly returned to the OS; only when the heap itself is destroyed. This means that the footprint of the heap is equal to its high watermark.
In return for this tradeoff, the allocator's overhead is strictly a function of (a) this watermark at any given time and (b) the number of allocations and their sizes. Compare this to malloc(), in which the order of allocation also gives different fragmentation patterns.
I also added some small things: