| ▲ | leumassuehtam 6 hours ago |
| > 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.
> TigerStyle It's baffling that a technique known for 30+ years in the industry have been repackage into "tiger style" or whatever this guru-esque thing this is. |
|
| ▲ | mitchellh 5 hours ago | parent | next [-] |
| Snide and condescending (or at best: dismissive) comments like this help no one and can at the extremes stereotype an entire group in a bad light. I think the more constructive reality is discussing why techniques that are common in some industries such as gaming or embedded systems have had difficulty being adopted more broadly, and celebrating that this idea which is good in many contexts is now spreading more broadly! Or, sharing some others that other industries might be missing out on (and again, asking critically why they aren't present). Ideas in general require marketing to spread, that's literally what marketing is in the positive (in the negative its all sorts of slime!). If a coding standard used by a company is the marketing this idea needs to live and grow, then hell yeah, "tiger style" it is! Such is humanity. |
| |
| ▲ | astrobe_ 4 hours ago | parent | next [-] | | Because garbage-collected languages are easier to teach and to use. So the low-level, low-resource or high-performance stuff is left to a handful of specialists - or "insects" according to Heinlein. Speaking of old things, this reminds me of one of Asimov's short stories, where someone who rediscovers mental calculus is believed to be a genius. | |
| ▲ | brabel 4 hours ago | parent | prev | next [-] | | > had difficulty being adopted more broadly Most applications don’t need to bother the user with things like how much memory they think will be needed upfront. They just allocate how much and when necessary. Most applications today are probably servers that change all the time. You would not know upfront how much memory you’d need as that would keep changing on every release! Static allocation may work in a few domains but it certainly doesn’t work in most. | | |
| ▲ | AlotOfReading 4 hours ago | parent | next [-] | | It's best to think of it as an entire spectrum from "statically allocate everything with compile time parameters" to "directly call the system allocator for every new bit of memory". It's just a helpful way to separate the concerns of memory allocation from memory usage. What this article is talking about isn't all the way at the other end (compile time allocation), but has the additional freedom that you can decide allocation size based on runtime parameters. That frees the rest of the application from needing to worry about managing memory allocations. We can imagine taking another step and only allocating at the start of a connection/request, so the rest of the server code doesn't need to deal with managing memory everywhere. This is more popularly known as region allocation. If you've ever worked with Apache or Nginx, this is what they do ("pools"). So on and so forth down into the leaf functions of your application. Your allocator is already doing this internally to help you out, but it doesn't have any knowledge of what your code looks like to optimize its patterns. Your application's performance (and maintainability) will usually benefit from doing it yourself, as much as you reasonably can. | |
| ▲ | chris- 2 hours ago | parent | prev [-] | | That's just saying "we push our memory problems up the stack so our clients / users need to deal with that". The reason this works is because human users in particular have become accustomed to software being buggy and failing often. | | |
| ▲ | brabel an hour ago | parent [-] | | What ?? It’s exactly the opposite of that! Memory allocation on demand frees users from having to worry about configuring memory settings, which static allocation requires except if you overallocate, which is problematic if lots of applications start doing. I absolutely don’t like the argument that memory is nearly free! Most laptops still come with around 8GB of RAM which a browser by itself can consume already … there’s really not a lot left when you also got Docker, compilers, music app, email and so on running. I have 64GB and still have to close apps sometimes because software nowadays does stupid things like overallocating. Don’t do that. |
|
| |
| ▲ | pjmlp 4 hours ago | parent | prev [-] | | It was a common practice in 8 and 16 bit home computing. |
|
|
| ▲ | jandrewrogers 5 hours ago | parent | prev | next [-] |
| Static allocation has been around for a long time but few people consider it even in contexts where it makes a lot of sense. I’ve designed a few database engines that used pure static allocation and developers often chafe at this model because it seems easier to delegate allocation (which really just obscures the complexity). Allocation aside, many optimizations require knowing precisely how close to instantaneous resource limits the software actually is, so it is good practice for performance engineering generally. Hardly anyone does it (look at most open source implementations) so promoting it can’t hurt. |
| |
| ▲ | wahern 25 minutes ago | parent [-] | | I've always thought static allocation was why we got overcommit[1] in Linux and its infamous OOM killer. In the 1990s big boy commercial databases assumed specialized admins, and one of their tasks was to figure out the value for the memory allocation setting in the DB configuration, which the DB would immediately allocate on startup. As a magic value, the easiest path forward was just to specify most of your RAM. DBs used to run on dedicated machines, anyhow. But then Linux came along and democratized running servers, and people wanted to run big boy databases alongside other services like Apache. Without overcommit these databases wouldn't run as typically configured--"best practice" allocation advice used up too much memory, leaving nothing for the rest of the services, especially on the more memory-constrained machines people ran Linux. Because on a typical system most of the memory preallocated to the DB was never used anyhow (the figure wasn't actually carefully chosen as intended), or the DB was designed (or at least the manual's written) with bigger machines in mind, and Linus wanted things to Just Work, whether experienced admins or not, the easy fix was just to overcommit in the kernel, et voila, a pain point for people dabbling with Linux was solved, at least superficially. NB: I was just a newbie back then, so any older grey beards, please feel free to correct me. But I distinctly remember supporting commercial databases as being one of the justifications for overcommit, despite overcommit not being typical in the environments originally running those DBs, AFAIU. [1] Note that AFAIU the BSDs had overcommit, too, but just for fork + CoW. Though these days FreeBSD at least has overcommit more similar to Linux. Solaris actually does strict accounting even for fork, and I assume that was true back in the 90s. Did any commercial Unices actually do overcommit by default? |
|
|
| ▲ | matklad 3 hours ago | parent | prev | next [-] |
| To add more context, TigerStyle is quite a bit more than just static allocation, and it indeed explicitly attributes earlier work: > NASA's Power of Ten — Rules for Developing Safety Critical Code will change the way you code forever. To expand: * https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TI... * https://spinroot.com/gerard/pdf/P10.pdf |
| |
| ▲ | kibwen 3 hours ago | parent [-] | | Those guidelines are quite clear that they're written specifically in the context of the C programming language, and may not make sense in other contexts: "For fairly pragmatic reasons, then, our coding rules primarily target C and attempt to optimize our ability to more thoroughly check the reliability of critical applications written in C." A version of this document targeting, say, Ada would look quite different. | | |
| ▲ | AlotOfReading 2 hours ago | parent | next [-] | | The JPL C rules are quite old, but avoiding dynamic allocation outside initialization is am considered best practice for spaceflight software regardless of language. Here's the recommendation from NASA's language-agnostic cFS: 4.2.4 Consolidate Resource Allocations
It is generally recommended to consolidate resource allocations to the application initialization function(s). Allocations and setup of resources such as memory pools and child tasks should happen once during initialization in order to provide more determinism during run time.
From:
https://github.com/nasa/cFE/blob/main/docs/cFE%20Application...The ESA Ada standard also recommends all allocation occur at initialization, and requires exceptions to be justified. | | |
| ▲ | kibwen 33 minutes ago | parent [-] | | > The JPL C rules are quite old, but avoiding dynamic allocation outside initialization is am considered best practice for spaceflight software regardless of language. The rules are written with the historical context of C making it too easy to leak heap-allocated memory. In the safety-critical Rust code that I've worked on, we tend not to dynamically allocate due to the usual constraints, and we're well aware of the "thou shalt not allocate" rules in the scripture, but we've already gotten clearance from the relevant certification authorities that Rust is exempt from the restriction against dynamic allocation specifically because of its ownership system. |
| |
| ▲ | matklad an hour ago | parent | prev [-] | | They do make a lot of sense in other contexts :-) From the actual rules, only #2 (minimize preprocessor) and #10 (compiler warnings) are C specific. Everything else is more-or-less universally applicable. |
|
|
|
| ▲ | codys 5 hours ago | parent | prev | next [-] |
| It seems it's just a part of a doc on style in tigerbeatle, in a similar way to the various "Google Style Guide" for code. These rarely have something new, but document what a particular project or organization does with respect to code style. |
|
| ▲ | addaon 6 hours ago | parent | prev | next [-] |
| Yep. Those of us who write embedded code for a living call this “writing code.” |
| |
| ▲ | nickmonad 6 hours ago | parent [-] | | Author here! That's totally fair. I did learn this is a common technique in the embedded world and I had a whole section in the original draft about how it's not a super well-known technique in the typical "backend web server" world, but I wanted to keep the length of the post down so I cut that out. I think there's a lot we can learn from embedded code, especially around performance. | | |
| ▲ | titzer 4 hours ago | parent [-] | | Back in 2005 Virgil I, which target MCUs like AVR, had static initialization and would generate a C program with all of the heap statically allocated, which was then compiled into the binary. C programmers for AVR are used to just declaring globals, but Virgil allowed arbitrary code to run which just initialized a heap. Virgil II and III inherited this. It's a standard part of a Virgil program that its components and top-level initializers run at compile time, and the resulting heap is then optimized and serialized into the binary. It doesn't require passing allocators around, it's just part of how the language works. |
|
|
|
| ▲ | publicdebates 4 hours ago | parent | prev | next [-] |
| > a technique known for 30+ years in the industry have been Knowledge sharing with next generations is one of those very tricky things. For one thing, how would I know where to find this? What book? What teacher? There are so many books, must I read all of them? What if my coworkers awaren't aware of it, how can they share it with me? Also, an old saying goes, if you're good at something, never do it for free. This isn't exactly a trade secret, but how many people blog about every advanced technique and trick they know? I blogged about how to create real C function pointers from Lua closures, as a way to advertise for my product, but that could very well have been kept a trade secret (and probably should have, as I got 0 sales from that blog post still). Why would anyone want to share this "tiger style" knowledge with newer generations with no personal benefit? Aren't they incentivized to use it secretly, or maybe write it in a book, or blog about it for advertising? |
| |
| ▲ | Nevermark 3 hours ago | parent | next [-] | | Trade secrets are not necessary to build up interest/visibility momentum. And likely "wasted" for external rewards, without pre-existing momentum. (External = a marketing/sales bump. vs. Internal = enjoy sharing, writing to self-clarify, writing practice.) Developing the abilities to repeatedly pick attractive topics (not as widely known as they are useful/interesting), and communicating (in a clear well-received voice/style), until those are validated by increasing visibility and sales/marketing impact, is where to start. After that, the choice to share a trade secret can be made based on a more predictable reward trade off. But every post already made, is a post to build on. | |
| ▲ | mytailorisrich 2 hours ago | parent | prev [-] | | I'd say usually you learn those techniques when you join a company as a junior dev and come in contact with engineers with decades of experience and systems that have been in production for years, too. I think it's when people consider that anything more than 5 years old is ancient and dismiss it that we lose established techniques and knowledge that we are then bound to rediscover again and again. |
|
|
| ▲ | zozbot234 3 hours ago | parent | prev | next [-] |
| > All memory must be statically allocated at startup. No memory may be dynamically allocated (or freed and reallocated) after initialization ... It's baffling that a technique known for 30+ years in the industry have been repackaged This is also how GPU shader programming works: there's no real equivalent to heap allocation or general pointers, you're expected to work as far as possible with local memory and sometimes preallocated shared buffers. So the technique may be quite relevant in the present day, even though it has a rather extensive history of its own. |
|
| ▲ | testdelacc1 6 hours ago | parent | prev [-] |
| It is known, but not widely used outside of embedded programming. The fact that they’re using it while writing a database when they didn’t need to makes people sit up and notice. So why did they make this conscious choice? It’s tempting to cut people down to size, but I don’t think it’s warranted here. I think TigerBeetle have created something remarkable and their approach to programming is how they’ve created it. |
| |