This article is quite long, and spends many kilobytes to make the following points (AFAICT):
- Pure malloc/free allocation is error-prone and expensive; it's too granular in many cases.
- Stack allocation has obvious limitations due to its LIFO nature. RAII has similar limitations.
- Let's use a bunch o separate, independent allocators / memory arenas instead. We can free them more quickly in one go when needed. We can group objects by lifetime using them. Having thread-local arenas naturally separates thread-local allocations from program-global allocations.
This sounds pretty reasonable, and, AFAIK, Zig leans heavily on this concept. I wonder if Rust can reap some of the benefits of arena-based allocation by leveraging its lifetime tracking.
This approach to memory management is completely at odds with the whole point of Rust.
Object orientated programming has conditioned programmers into believing that having a hairy nest of small allocations, all with pointers to each other, is the normal, unavoidable situation.
In fact, it creates all sorts of problems. First, and most obviously, it's really hard to keep track of all those allocations, so you get leaks, and use after free, and all the other familiar memory bugs. But you also get bloated memory use, with both your user code, and the allocator having to keep track of all those chunks of memory. You get poor cache utilisation. You incur often ridiculous CPU overhead constructing and tearing down these massive, intricate structures.
Rust makes it harder to trip over the memory bugs, but that makes it easier to keep on using the lots-of-tiny-allocations paradigm, which is a much bigger problem overall.
> We can free them more quickly in one go when needed. We can group objects by lifetime using them. Having thread-local arenas naturally separates thread-local allocations from program-global allocations.
These are at odds due to concurrency and object lifetimes. Reaching into memory allocated by another thread on another core was never free but has only gotten more costly.
You can either pay more at allocation time, use time, or have a copying collector. But you have to deal with at least one.
So for a cache or a lazily loaded lookup table, you want an arena allocator. But the same data structure used within the scope of say a single request should be a thread local arena.
> The key point being, this allows a language like Rust to completely side-step the borrow checker and allow us to do "manual memory management with arenas" without actually touching any hairy pointers, and while remaining 100% safe. If there was one thing to point at that I like about Rust, it'd be this. Especially with a library like thunderdome it really feels that this is a great match, and that this data structure very well fits the language as it was intended.
It seems like the choice of a stacklike Arena API makes the examples a little more confusing than needed. An arena doesn't necessarily mean allocation 2 must be freed before allocation 1.
If this seems cool to you, check out Zig. The libraries use a similar convention where code that might allocate requires passing an allocator, which may be an arena, or something cool we don't even know about yet.
I am sure the video above will cause immediate disagreement (I think it goes too far on some topics), but I urge people to consider the ideas contained within.
(I seem to have mis-posted this to another thread?)
This article is quite long, and spends many kilobytes to make the following points (AFAICT):
- Pure malloc/free allocation is error-prone and expensive; it's too granular in many cases.
- Stack allocation has obvious limitations due to its LIFO nature. RAII has similar limitations.
- Let's use a bunch o separate, independent allocators / memory arenas instead. We can free them more quickly in one go when needed. We can group objects by lifetime using them. Having thread-local arenas naturally separates thread-local allocations from program-global allocations.
This sounds pretty reasonable, and, AFAIK, Zig leans heavily on this concept. I wonder if Rust can reap some of the benefits of arena-based allocation by leveraging its lifetime tracking.
This approach to memory management is completely at odds with the whole point of Rust.
Object orientated programming has conditioned programmers into believing that having a hairy nest of small allocations, all with pointers to each other, is the normal, unavoidable situation.
In fact, it creates all sorts of problems. First, and most obviously, it's really hard to keep track of all those allocations, so you get leaks, and use after free, and all the other familiar memory bugs. But you also get bloated memory use, with both your user code, and the allocator having to keep track of all those chunks of memory. You get poor cache utilisation. You incur often ridiculous CPU overhead constructing and tearing down these massive, intricate structures.
Rust makes it harder to trip over the memory bugs, but that makes it easier to keep on using the lots-of-tiny-allocations paradigm, which is a much bigger problem overall.
> We can free them more quickly in one go when needed. We can group objects by lifetime using them. Having thread-local arenas naturally separates thread-local allocations from program-global allocations.
These are at odds due to concurrency and object lifetimes. Reaching into memory allocated by another thread on another core was never free but has only gotten more costly.
You can either pay more at allocation time, use time, or have a copying collector. But you have to deal with at least one.
So for a cache or a lazily loaded lookup table, you want an arena allocator. But the same data structure used within the scope of say a single request should be a thread local arena.
> I wonder if Rust can reap some of the benefits of arena-based allocation by leveraging its lifetime tracking.
I'm reminded of one positive remark made here: https://loglog.games/blog/leaving-rust-gamedev/#ecs-solves-t...
> The key point being, this allows a language like Rust to completely side-step the borrow checker and allow us to do "manual memory management with arenas" without actually touching any hairy pointers, and while remaining 100% safe. If there was one thing to point at that I like about Rust, it'd be this. Especially with a library like thunderdome it really feels that this is a great match, and that this data structure very well fits the language as it was intended.
Yes, you can have memory safe arenas in Rust, as with Bumpalo.
It seems like the choice of a stacklike Arena API makes the examples a little more confusing than needed. An arena doesn't necessarily mean allocation 2 must be freed before allocation 1.
If this seems cool to you, check out Zig. The libraries use a similar convention where code that might allocate requires passing an allocator, which may be an arena, or something cool we don't even know about yet.
The author's defense of C reminds me of this classic youtube video: https://www.youtube.com/watch?v=443UNeGrFoM&pp=ygUPaG93IGkgc...
I am sure the video above will cause immediate disagreement (I think it goes too far on some topics), but I urge people to consider the ideas contained within.
(I seem to have mis-posted this to another thread?)
Another use case is a per-request arena for a web server.
If PHP did one thing right, it is this: allocate resources while handling a request, free them all unconditionally when the response has been sent.