4 ms·
Ya that's what I wanted too. I'm actually flabbergasted that malloc() isn't a blocking call on most OSs, that would wait until the requested amount of memory wa
by zackmorris 1y ago
Ya that's what I wanted too. I'm actually flabbergasted that malloc() isn't a blocking call on most OSs, that would wait until the requested amount of memory was available before returning. That way programs would just suspend/resume as needed in low memory situations, rather that crashing. A process viewer could show which programs are blocked waiting for more memory, and users could optionally resume them manually. We could even serialize and unserialize entire programs and have them resume when enough memory is available.
This one simple thing would have freed users from running under the assumption that programs can crash at any time, and allowed them to operate at a higher level of abstraction to get more real work done.
This missed opportunity with a blocking malloc() is one of any number of obscene design decisions that I can't unsee in the tech status quo.
In my experience, basically all software bugs stem from asynchronous/nonblocking behavior. Because it's difficult to prove that async code is deterministic without coming full circle and restructuring it as sync. For example, higher-order methods like map/reduce and scatter/gather arrays can replace iterators. And this can now be done automagically by LLM code assistants, and static analyzers since the middle of last century. Once we see that this is possible, especially if we use all const variables to avoid mutation (mostly future-proofing our logic), it's hard to avoid asking ourselves why we're all doing it the hard way. We should be able to click a block of code and choose "make sync" or "make functional" and vice versa. So that beginners could write batch files and macros with familiar iteration syntax and transpile it to safe and reliable functional code. And experts could write pure functional code in shorthand and export it as imperative code for others to verify.
This was always another dream of mine, since I've been waiting for big companies to do it since the mid 1990s but they can't be bothered, yet I'll likely spend the rest of my life building CRUD apps to make rent.
- jeroenhd 1y ago> I'm actually flabbergasted that malloc() isn't a blocking call on most OSs, that would wait until the requested amount of memory was available before returning. In many cases, the memory is "available" in the form of swap space (once other applications are swapped out). In other cases it's hard to tell how much memory is available (swap space can be variable, like with compressed swap space/compressed memory). It's not that hard to write your own malloc() that does this, of course; all you need is a quick wrapper like void* malloc_blocking(size_t size) { void* out; do { out = malloc(size); if (out == NULL) usleep(100000); } while (out == NULL); return out; } The problem with this "solution" is that malloc almost never fails. Applications don't typically handle malloc failure well, either; very few pre-allocate all the resources necessary to even log and notify the user of a memory allocation failure, let alone fail gracefully. In my experience, Windows deals with low-memory situations a lot better. It has APIs notifying applications that memory is running low so they can clear caches (i.e. by using CreateMemoryResourceNotification) and will often try to extend the page file temporarily rather than kill applications if it can help it. On Linux, you can measure the system memory state and application memory usage in a loop (do you check /proc/meminfo or the cgroup API? If so, which version? Good luck figuring that out!) but you're still left to the whims of the OOM daemon. You cannot just "make sync" everything. Asynchronous code isn't written to make your life harder. It increases throughput and performance. That's why Rust still allows for asynchronous code in various methods (threads and async) with a whole type system to make memory exchange safe while maintaining performance. Also, I've very rarely encountered bugs in any code I've debugged that are caused by asynchronous/nonblocking behaviour. You get a deadlock every now and then, but most bugs are either in the business logic layer or in code making assumption about things like "variables being initialized by the caller" and "pointers not being freed when used" or even just "pointers not being null". Using better languages and actually leveraging the many tools available these days can prevent most of those bugs.