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.
[–] grg0 2 days ago
[–] the-tomster 2 days ago
Two options: you either say "eh 20MB per request ought to be big enough" and resize it later if you need to. Or you take time to figure out reasonable limits in terms of whatever domain you're dealing with, and return descriptive errors when those limits are exceeded. Maybe you're saying your service supports up to N HTTP headers and M query parameters in the URL and so on. For almost anything there's a limit you can place that's reasonable. Having no limits at all just means the limit is when you run out of memory / disk / whatever.
If you like RAII and C++ just use that though, Zig is an alternative not an upgrade, imo.
[–] grg0 1 day ago
Resize: realloc invalidates pointers. If you're saying allocate more chunks and link them, that is technically no longer an arena?
Requesting virtual memory and committing lazily seems a good trade-off except on Windows, which does not allow to over-commit. Somehow I don't find that very satisfying because it relies on the OS and on the hardware to provide virtual memory support. But maybe it's just what it is.
[–] MrBuddyCasino 1 day ago
[–] the-tomster 1 day ago
If you're doing something like per-request or per-frame arenas you can clear the arena without having to reallocate the whole mapping. And depending how fancy you want to get you can mark the pages unused when you clear the arena so that the OS can reclaim them if needed.
[–] rallyroger 1 day ago
Should you allow an http-server to allocate unbounded request sizes? Seems like it would lead to an easy denial of service.
[–] lenkite 2 days ago
All HTTP servers have a configurable maximum request size. Ex: client_max_body_size in Nginx.
[–] i2talics 2 days ago
I mean push in the sense of a pit-of-success, not making me do things because the alternative is unpalatable.
> managing frees one-to-one with allocations is a nightmare
It really isn't a nightmare if your language has tools to help you. I'm never particularly concerned about frees in Rust outside of thinking about room to optimize.
> Need something to live across connections? Use the general purpose allocator for those particular things.
Well, this is a determination you have to make very carefully and if you screw it up (like in the situation I was trying to outline) you have a subtle bug.
> 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.
What's also fine is using malloc, which will have perfectly reasonable performance for your toy programs.
This is reinforcing my belief that Zig programmers actually just have a sort of aesthetic attachment to the idea of managing their allocations themselves and this has very little to do with the actual practical concerns of writing software that works. I'm a lot more sympathetic to the other reply that talked about library code improving flexibility for those relying on the library, than this comment that only thinks about the case where everything goes perfectly and using a fixed size buffer for no reason.
[–] nvme0n1p1 2 days ago
Zig's position, love it or hate it, is that you should be thinking about it. Dropping a Vec<String> in Rust is O(n). Have you ever clicked the X on an app and it takes 10 seconds to disappear? Stuff like this is part of the problem. You shouldn't have to traverse your process's whole memory space just to call exit(0).
If you have to write that for loop, the O(n) will jump out at you and push you towards an arena or FixedBufferAllocator or std.process.cleanExit, or any other solution to avoid the loop.
[–] kibwen 2 days ago
[–] lunar_mycroft 1 day ago
> Dropping vecs that contain strings does not make any Rust code in the real world slow. You would need to have a vec containing billions of strings, occupying several gigs of memory
I actually had a hobby project where that became very noticeable/too slow for my requirements at around 800k Strings, so several orders of magnitude less than your estimate. Switching to a solution that freed all the memory at once predictably made it run effectively instantly.
> And for extreme cases like that, you can simply use arenas
I think this is a fundamentally flawed way of thinking about things. Yes, each individual string allocation and drop isn't going to cost much, but in combinations with all the other similar decisions you're likely making if you think this way, plus the decisions of library authors, etc, it can add up even if strings specifically aren't a major problem. Avoiding pessimization by default instead of only when you can't ignore them any more is a good habit to be in.
[–] kibwen 1 day ago
[–] lunar_mycroft 1 day ago
(Also, you do not need to sell me on bumpalo, I use it heavily already)
[–] tialaramex 1 day ago
Measure, measure, measure.
So often when people insist that a thing they don't like is "part of the problem" they haven't even thought about how much that "part" would be, although I suppose it's worse when they have thought and decided to go ahead anyway because the weasel wording might convince the hard of thinking.
A guy who rounded up from $14.86 to $15 on some grant paperwork and got 14 cents he wasn't entitled to out of a government programme, and Ken Paxton inexplicably becoming very wealthy from a government job are both "part of the problem" but hopefully it's apparent which of these is worth fixing.
[–] simonask 2 days ago
(There are cases where it also takes time because the OS does have to flush all open files during process teardown, etc., but this shouldn't generally be user-visible.)
[–] the-tomster 2 days ago
Indeed if you don't want to manage everything yourself I don't think there's a need to use Zig. The whole pitch is making everything explicit and not hiding control flow. And I do think that limits its usefulness to smaller-scale codebases.
Writing quality software doesn't require much from the programming language until your codebase gets very large and you're collaborating with a ton of people. If I'm expecting a codebase to grow to a large scale I'm not reaching for Zig for that. I don't trust _myself_ to keep that much Zig code tidy and correct let alone a big mob of developers and agents :)
[–] alextingle 1 day ago
With a small program, it's rarely difficult to work out what's going on. If your small program develops a performance problem, it's usually fairly tractable to work out what's going on, and modify it. In extremis, you can just rewrite the whole thing.
Large programs are another matter. Hidden control flows in C++ (for example) can make pinning down performance problems extremely difficult. And then widespread refactoring can be extremely challenging.
Zig forces everything to be an explicit interface, which should make maintenance work on large programs much more tractable.
And how do you size the arena?
> keep track of them individually
I think this is an exaggeration of the problem. This is what RAII semantics in C++ are for.
> avoiding that kind of invisible code
The invisible code is traded for defer statements right after initialization that are obvious and therefore mostly just noise, and also a problem if you forget to call them. This isn't an issue with RAII. I get the point of not wanting invisible code, but defers don't seem much of an improvement either. A trade-off at best.