logoalt Hacker News

i2talics • yesterday at 11:01 PM • 3 replies • view on HN

Why does everyone love being able to control the allocator in Zig? I rarely want this low level control over the allocator, I would rather have an easy to use interface to malloc/free (such as RAII) or would prefer the language push me to avoiding allocations when unnecessary. C and Zig users are always talking about how arena allocators are easier to use than the alternative but I disagree because the alternative is extremely easy to use when the language makes it so.

Arenas have a lot of footguns like growing out of control if you don't have space in your logic to delete them (e.g. suppose every new HTTP connection required obtaining a new allocation from the primary arena -- now you have a memory leak). They also aren't necessarily faster than malloc: I remember hearing a case where mimalloc was faster than an arena for a one-shot program like a linker because reclaiming space improved cache locality. Plus it's difficult to implement things like growable vectors or hashmaps using an arena without wasting space.

I just don't see how "futz about with the allocator constantly" and "use an arena" is actually a good default.


Replies

the-tomster • yesterday at 11:26 PM

If you don't like arenas then that will push you towards avoiding allocations :)

I don't love malloc / free, managing frees one-to-one with allocations is a nightmare. An HTTP server is actually a great example of a good fit for arenas... you can have an arena created per connection, and then free the arena when the connection closes. Now all of your allocations during that connection are guaranteed to be freed instead of having to keep track of them individually. Need something to live across connections? Use the general purpose allocator for those particular things.

For one shot programs, why bother freeing anything at all? The gpa or malloc or whatever else is fine there.

Personally I mostly lean on fixed-size buffers, but if I'm writing Zig it's just little toy programs where blowing up when the buffer runs out of room is fine. But for big non-toy programs it might be good to use fixed-size buffers anyway and define your limits in terms of things actually relevant to your domain.

RAII and smart pointers are fine too, but C++ has you covered if you want those. Zig is specifically avoiding that kind of invisible code that destructors bring you.

➕ show 1 reply
awesan • yesterday at 11:06 PM

It is a good default for lib code because it makes that code truly re-usable. The same is true for great C libraries, they let you provide a block of memory instead of calling malloc inside. The library should not get to decide if/when allocations should be done.

In Zig app code you don't have to pass allocators all over if you don't want to, that's your code so do what you want. But for libraries it's the right thing to do because it puts the caller in control.

The reason you have to pass allocators instead of making this implicit like in e.g. Odin, is because Zig just takes a firm stance against implicit logic, firmer than any other language I've ever used. The end result is that people who like Zig tend to like passing allocators around even in their own code.

➕ show 1 reply
elendilm • yesterday at 11:21 PM

mimalloc aggressively reclaims space and it benefits the use case in our Dip database built on rust.

This is for a long running process where consuming compute and memory should only occur on processing a request and must revert to a baseline memory consumption once the request is completed.

malloc with default allocator always gradually increases the memory consumption. This continues with enough request bursts on our testing until the process runs out of memory. mimalloc doesn't.

On mobile, we are stuck with the default allocator. On mobiles, the phenomenon of the default allocator consuming memory is reproducible even with normal Qt apps. It is what it is.

➕ show 1 reply