Still, any serious developer should, at the very least, have the patience to interrogate their code.
No need to go back later and add a bunch of free(), because you correctly implemented the memory policy as a matter of course, in two lines.
In Zig, everything which allocates receives an allocator to do so. So writing a top-to-bottom program of the sort indicated in the GP post, you're going to make an allocator first thing. That's when you decide to use an arena, and defer it, and you're done.
You wouldn't decide to use malloc (which is available), or the GeneralPurposeAllocator, and then "end up with the same mess" by forgetting to release any of the memory, because the debug release mode, where all the work gets done, will loudly complain about that. It would take real stubbornness and conviction to write an all-malloc-no-free program in Zig, but using an arena is cheap and easy.
So yes, it has everything to do with a particular language. If you wrote it in Rust, you'd end up with a borrow-checker-compatible program, if you wrote it in Nim, allocation would be taken care of by the runtime. In C, it's tempting to just use malloc and let the operating system do the GC when the process exits.
Unless you know you will only allocate 100x times less memory than the average user has it will bite you.
1. Your code is now fragile (in the taleb sense).
2. Your code is now unusable when someone wants to use it as a library in the future
3. You are now prone to memory fragmentation (many use a bump the pointer allocator when not freeing).
4. You encourage people to not care about free-ing anything — when you do turn free on, or turn a GC on, you might struggle to actually free anything because of references all over the place.
Walter did this in the DMD compiler years ago and it gave a drastic performance boost. [0]
> You are now prone to memory fragmentation (many use a bump the pointer allocator when not freeing)
Pointer-bump allocation is immune to fragmentation by definition, no?
Keeping dead objects around might lead to caches filled with mostly 'dead' data though.
[0] https://web.archive.org/web/20190126213344/https://www.drdob...
Anecdotally people have told me that's it's faster with a modern malloc impl anyway, haven't tried it properly.
> Pointer-bump allocation is immune to fragmentation by definition, no?
In some sense yes but what I mean is that like should end up near like whereas if you have everything going through a single bumping allocator then you can have a pattern of
ABABAB where a proper allocator would do AAABBB which the cache can actually use.
This sounds like guesswork. Do you know the details of DMD's internals? Have you done profiling to confirm poor cache behaviour?
Again, per the article I linked, when Walter made the change there was a drastic improvement in performance.
> everything gets copied so much (because copies are cheap right?)
I'm not sure what copying you're referring to here. Declining to call free has nothing to do with needless copy operations.
> like should end up near like whereas if you have everything going through a single bumping allocator then you can have a pattern of ABABAB where a proper allocator would do AAABBB which the cache can actually use.
A general purpose allocator like malloc can't segment the allocations for different types/purposes, it only has the allocation size to go on. That's true whether or not you ever call free. If you want to manage memory using purpose-specific pools, you'd need to do that yourself.
As for whether this really would improve cache performance, I imagine it's possible, which is why we have discussions about structure-of-arrays vs array-of-structures, and the entity component system pattern used in gamedev. I'd be surprised if compiler code could be significantly accelerated with that kind of reworking, though.
Think.
You make malloc feel inexpensive both by using a crappy but fast allocator and disabling free. People (reflexively) know this, and then they don't get punished when they get extremely careless with their allocations because test suites never allocate enough memory to OOM the machine.
This isn't some hypothetical, I have measured the amount of memory dmd ever actually writes to (i.e. after allocation) to be absurdly low. Like single digits.
Pretty much every bit of semantic analysis that hasn't been optimized post-facto involves copying hundreds to thousands of bytes.
> A general purpose allocator like malloc can't segment the allocations for different types/purposes, it only has the allocation size to go on. That's true whether or not you ever call free.
The size is what I'm getting at, but a D allocator can do this because it gets given type information. (dmd allocates mainly with `new` which is then forwarded to the bump the pointer allocator if the GC is not un-disabled)
Also evidence that the exact scheme dmd uses is suboptimal wrt allocator impl:
https://forum.dlang.org/thread/zmknwhsidfigzsiqcibs@forum.dl...