For example, this could be important in systems where you might be controlling physical hardware at the same time as reading commands from a network. It's probably a good idea to maintain control of the hardware even if you don't have enough memory right now to read network commands.
Prior to swap and excessive abuse of virtual memory this was not an option: If you gave up on running out of memory, your users gave up on your application. On the Amiga, for example, being told an operation failed due to lack of memory and given the chance to correct it by closing down something else was always the expected behaviour.
But try having allocations fail today, and watch the mayhem as any number of applications just fall over. So we rely on swap, which leaves systems prone to death spirals when the swap slows things down instead.
If embedded systems programmers wrote code the same way modern desktop applications developers did, we'd all be dead.
I think, in most computing environments, it should be the operating system's responsibility to inform the user that free memory is running out. Applications should be able to assume that they can always get memory to work with.
I think the swap is an extremely sensible solution, in that executing programs slowly is (in most environments, including desktop) better than halting programs completely. It provides an opportunity for the user to fix the situation, without anything bad happening. Note that the swap is optional anyway, so don't use it if you don't like it.
Comparing modern computing environments to the Amiga is laughable. It's not even comparable to modern embedded environments, because they serve(d) different purposes.
I'm a hobbyist C application/library developer who assumes memory allocation always works.
As a user, I find it incredibly frustrating when my old but indispensable music software runs out of address space (I have plenty of RAM) and, instead of canceling the current operation (e.g. processing some large segment of audio), just dies with a string of cryptic error dialogs. The best thing for the user in this case is to hobble along without allocating more memory, not to fail catastrophically by assuming that memory allocation always works.
Swap is not a good solution because when there's enough swap to handle significant memory overuse, the system becomes unresponsive to user input since the latency and throughput to swap are significantly slower than RAM.
Your music software's problem seems to be a bad algorithm - not that it doesn't check the return values of the `*alloc` functions.Aas you say, it should be able to process the audio in constant space. While I assume that I can always acquire memory, I do still care about the space-efficiency of my software.
I must admit I've never seen my system depending on swap, so I don't know how bad it is. But, if you have 1GB of on-RAM memory already allocated, wouldn't it only be new processes that are slow?
Also, I'd again point out that if you don't like swap, you don't have to have one.
No - the memory sub system, will swap out pages based on usage and some other parameters. A new application would most likely result in already running applications least used pages being swapped out.
Just for fun, try deliberately creating a swap storm some time. Then try to recover from it :-). Do this on a system that doesn't have other users.
If Boeing made passenger jets the way Boeing made fighters, we'd all be dead, too, but try telling a fighter pilot that they should do their job from a 777. It's two very different contexts.
Besides, some errors can't be recovered from. What do you do when your error logging code reports a failure? Keep trying to log the same error, or do you begin trying to log the error that you can't log errors anymore?
First you try to fix the problem of the logging system by runnig a reorganisation routine (delete old data,...) or reinit the subsystem. If that does not work AND if logging is a manadatory function of you system you make sure to change into a safe state and inidcate a fatal error state (blinking light, beeper, whatever). If the logging is such an important part of the system surrounding your system it might take further actions on its own and reinit your system (maybe turn your system off and start another logging systen). There is no exit. You never give up.
(Disclosure: I got OCD too, this is not meant to make C development hostile to people with OCD.)
If your intention is to continue running, then of course you want to call free() on your memory. And this certainly makes sense to do as you exit functions. But if you're, say, calling exit() in the middle of your program, for whatever reason, you don't need to worry about memory.
Other resources may be a problem, though. The the operating system will reclaim things it controlled, and granted to your process - memory, sockets, file descriptors and such. But you need to be careful about resources not controlled by the operating system in such a manner.
Some kernels may not get memory back by themselves and expect each application to give it back. We're lucky that the kernels we use everyday do, but we may one day have to write for a target OS where it's not the case. Just hoping "the kernel will save us" is a practice as bad as relying on undefined behaviors.
If you're coding correctly, you have exactly as much malloc()'s as you have free()'s, so when rewinding the stack to exit, your application is gonna free() everything anyway.
Speaking of resources, what about leftover content in FIFOs or shm threads that you just locked?
And when you got OCD, you're only satisfied with this:
$ valgrind cat /var/log/*
...
==17473== HEAP SUMMARY:
==17473== in use at exit: 0 bytes in 0 blocks
==17473== total heap usage: 123 allocs, 123 frees, 2,479,696 bytes allocated
==17473==
==17473== All heap blocks were freed -- no leaks are possible
==17473==
==17473== For counts of detected and suppressed errors, rerun with: -v
==17473== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
(cat was an easy choice and all I got on this box, but I've had bigger stuff already pass the "no leaks are possible" certification)Second, please re-read my last sentence. I specifically addressed things that the kernel does not reclaim. This would also include System V shared memory segments and the like. You must manage these yourself, and it is always messy. Typically, rather than calling exit directly, you're going to invoke a routine that knows about all such resources, frees them, then calls exit. But you still don't need to unwind your stack back to main.
Third, the kernel always gets back all of its memory that was granted through conventional means. That's what operating systems do. I think you have a fundamental misunderstanding of what malloc is, and where it lives. Malloc is a user-level routine that lives inside of your process. When you call malloc, it is granting you memory that you already own. Malloc is just a convenience routine that sits between you and the operating system. When you say malloc(4), it does not go off and request 4 bytes from the operating system. It looks into large chunks of memory the operating system granted to it, and gives you some, updating its data structures along the way. If all of its chunks of memory are currently allocated, then it will go ask the operating system for memory - on a Unix machine, typically through a call to brk to mmap. But when it calls brk or mmap, it will request a large amount of memory, say a few megabytes. Then, from that large chunk, it will carve out 4 bytes for you to use.
(This is why off-by-one errors are so pernicious in C: the chances are very good that you actually do own that memory, so the kernel will happily allow you to access the value.)
Now, even if you are a good citizen and return all memory to malloc, the operating system still has to reclaim tons of memory from you. Which memory? Well, your stacks and such, but also all of that memory that malloc still controls. When you free memory back to malloc, malloc is very unlikely to then give it back to the operating system. So all programs, at exit, will have memory that they own that the kernel will need to reclaim.