somewhat serious

Statically Allocated, For A Better World?

Note: Thoughts are a "seedling".


At this point in time, my day job consists of Clojure, some Python, JavaScript and a little bit o' Go.

The common thread: each of these tools take a "don't know, don't care" approach to memory from a programmers point of view. While this tradeoff usually allows for concerns to be placed elsewhere in order to have more engineering throughput, I wonder if this tradeoff is worthwhile in the long run.

I've been dipping my toes into Zig and its worldview. Zig has a fascinating, and challenging worldview. The reason for embarking on said journey was prompted by the fantasically displayed craft of the TigerBeetle folks. I then looked at TigerBeetle repo and found the Tiger Style doc. One of the more interesting principles I read was:

All memory must be statically allocated at startup. No memory may be dynamically allocated (or freed and reallocated) after initialization. This avoids unpredictable behavior that can significantly affect performance, and avoids use-after-free. As a second-order effect, it is our experience that this also makes for more efficient, simpler designs that are more performant and easier to maintain and reason about, compared to designs that do not consider all possible memory usage patterns upfront as part of the design.

Which, according to the code, is an arena allocator.

Given my background is geared toward "web programming", I tend to think of concepts such as static allocation in said context.

The implication of statically allocating memory at start time has an interesting property which seems like it may make web services better over time, but be a worse developer experience for most developers. Makes me wonder who the customer really is...

Anyway, the real benefit would be in operations. If you know that your max request lifecycle is capped at 100KB, and at startup 1 GB of RAM is configured, the max concurrency at a single point in time is 10,000 requests, which means that the theoretical requests per second is ~165, which means you could hit that max if your services internal latency was ~16ms, which if the service is networked, is unlikely.

All that to say, from a busniess perspective, not only does it mean we know how much machine we need, but we also know the hard limits and know how to scale accordingly.

It is difficult to capacity plan with a GC'ed language listed above. The strategy is pretty much deploy it on some reasonable infra, monitor it for awhile, hope it doesn't fall over, and if it doesn't there is a rough hueristic of how much a thing scales.

You could also have some auto-scaling rules, but that doesn't solve the fundamental problem of the GC being a mystical being that you hope you appease every time a new version is released.