diff options
Diffstat (limited to 'notes/260922-use-alloc-3.md')
| -rw-r--r-- | notes/260922-use-alloc-3.md | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/notes/260922-use-alloc-3.md b/notes/260922-use-alloc-3.md index abe520d..fc87293 100644 --- a/notes/260922-use-alloc-3.md +++ b/notes/260922-use-alloc-3.md @@ -1,9 +1,12 @@ # Using Meta Alloc, Attempt 3 +<!--TOC--> + _2026 September_ Here's a fairly concrete design proposal. + ## Block Alloc This is a simple manual alloc/free allocator, based on the Meta Alloc @@ -27,6 +30,7 @@ the Meta Alloc limitation of 256 GiB total heap / 16 GiB per slab. (Every four size classes, roughly; first few classes being exceptions e.g. 8-byte size class gets an entire slab for itself.) + ## GC Alloc A fully concurrent (virtually "zero pause") mark-sweep tracing GC @@ -97,6 +101,8 @@ barriers with colored pointers and whatnot, like ZGC. It's unclear whether the CPU overhead would be justified; all it gives you is potentially improved spatial locality of objects in memory. +### Pinning + Oh, and with regards to object pinning, Gemini gave me a really cool idea on how to do it efficiently: @@ -133,3 +139,55 @@ and unfortunately there's three of them, but that still gives us: (3 * 640 MiB) / 256 GiB ~= 0.73% metadata overhead That's quite good I think. + +### Explicit free + +As an optimization trick offered to application code that otherwise +uses GC, there could be a special explicit `gc_free()` function. + +This would clear the GC occupancy bit for the given memory slot, and +place it into the thread-local allocation buffer. (The same that's +fed from the global shared free-list for a size class.) + +Clearing the occupancy bit ensures that the sweep phase doesn't touch +it and the block it's placed in can't be freed to Meta Alloc. It's +basically as if it had been swept by the GC, but lands immediately +within the thread-local alloc buffer. + +If the local buffer is full, I suppose a chunk of it would be flushed +into the shared free-list of the size class. Basically the same as +Block Alloc and Meta Alloc. That's somewhat costlier than simply +putting it into the local buffer, but should still remain under a +microsecond I suppose. + +This way, an application that allocates and frees a bunch of objects +in a tight loop could make sure that it keeps reusing the same few +memory slots already in L1D cache. + +If the allocation happens at the start of the loop and the freeing at +the end, then the programmer could have just used manual alloc/free, +or used stack memory, and a smart optimizer should even detect this +pattern and turn it into stack usage anyway... + +But if the loop crosses across module boundaries, conditionals are +involved, or it frees some old objects at the start of the loop and +then creates new ones or creates them at the end, I could see some +situations where this is a useful API to offer. + +(Conditional free is probably the strongest case; in all other cases +the object didn't need to be created with `gc_alloc()` to begin with, +I think. Haven't thought hard enough about it.) + +### GC handover + +An object initially allocated as a manually managed object could be +simply handed over to the GC, if there is some logical reason to do +such a thing. + +All this entails is setting the GC occupancy bit for the memory slot. +That's literally all; the object is now GC managed. + +Of course, if the object acts as the root of a whole graph of objects +that were manually allocated and are meant to be handed over to GC, +then a traversal of that graph may be necessary to hand all of them +over to GC. |
