Earlier quoted context omitted.
The malloc() function requests memory from the kernel using mmap(). If mmap() returns successfully, it means that the kernel is saying that the memory is allocated. So from malloc()'s perspective the memory allocation has been successful and it must return a non-null pointer to the caller. The standard does not require malloc() to distrust what the kernel said and try to actually write to that memory to double-check…
The standard literally could not care less if there's a kernel underneath. It doesn't care how malloc is implemented or what the kernel, if any, looks like "from its perspective". The perspective that has relevance is that of the caller of malloc. From your own quotes: > The pointer returned if the allocation succeeds is suitably aligned so that [...] > If the space cannot be allocated, a null pointer is returned. If…
Malloc Never Fails (2012)
81–90 of 165 posts
Re: Malloc Never Fails (2012)
#82The title here is just blatantly false; there are certainly some scenarios in which it won't fail, but many in which it will. The author is aware of this since he fixes the claim toward the end: > To clarify, the surprising behaviour malloc has does not mean we should ignore its return value. We just need to be careful because malloc returning successfully does not always mean that we can use the requested memory. It…
But many Linux applications assume the overcommit behavior. Its far easier to just "go with the flow" or "When in Rome...". Overcommit is the programming culture of Linux and should be assumed when writing Linux apps.
Re: Malloc Never Fails (2012)
#83What bothers me is that I read this train wreck without any red flags until I saw his correction at the end. Even the headline was wrong given the article, which itself was wrong. I really should have coffee before HN
Linux's Overcommit behavior is non-obvious to many programmers. Its one of those issues that very few programmers I've come across in the workplace understand properly.
This blogpost properly understands the issues associated with Overcommit, and have done some preliminary investigations that describe the behavior. Its a really good blogpost.
The general point of the blogpost is that "Malloc Fails due to address space exhaustion more often than actual memory-exhaustion". Because actual memory exhaustion causes OOM killer code to be run... and OOM killer is a non-obvious case of the Linux kernel.
Re: Malloc Never Fails (2012)
#84Earlier quoted context omitted.
> If the out-of-memory was caused by something simple like accidentally loading 2G of data because of some odd data in an network request or a user selected file, and it rolls back to the start of the UI action or the incoming network request, the application may still work fine. If you have a system that handles independent requests, it might be more robust to model each request as its own process, and then simply a…
It's certainly more robust, but a lot of overhead for what should be a very uncommon situation. In eg an application server, requests themselves may be independent, but still share a lot of cached data - and as long as locking overhead doesn't overwhelm you, a single process is still the fastest way to share data between (worker) threads.
If your threads need to share interleaved modifications to some common state then that approach isn't viable. But in that case it will be very hard to "roll back"/"skip over" a failed request, as it's difficult to be confident that you haven't corrupted that shared data in a way that will cause the same problem for future requests.
Re: Malloc Never Fails (2012)
#85Earlier quoted context omitted.
This is true, in my experience. If you keep your program fairly simple, implement it in plain C, avoid recursion, and keep these requirements in mind from the start, then it is possible to write a program that fails gracefully when it runs out of memory. Some old-school Unix daemons do this. But for most software it's impractical, so you might as well define your own xmalloc() that calls abort() if malloc() returns z…
An exception-safe C++ program can do the same through a std::bad_alloc exception. If the out-of-memory was caused by something simple like accidentally loading 2G of data because of some odd data in an network request or a user selected file, and it rolls back to the start of the UI action or the incoming network request, the application may still work fine. (I usually connected other out-of-resource conditions such…
Re: Malloc Never Fails (2012)
#86The title here is just blatantly false; there are certainly some scenarios in which it won't fail, but many in which it will. The author is aware of this since he fixes the claim toward the end: > To clarify, the surprising behaviour malloc has does not mean we should ignore its return value. We just need to be careful because malloc returning successfully does not always mean that we can use the requested memory. It…
n.b. turning over-commit off comes with its own set of problems, such as causing programs to fail long before all memory has really been exhausted. For example, fork() will have to ensure that there is enough memory for a complete copy of the running process. If you have a large process, e.g. using 4GB of a 8GB machine, then fork() won't be able to run, even if you just want to fork and run a tiny program. With over-…
Re: Malloc Never Fails (2012)
#87The title here is just blatantly false; there are certainly some scenarios in which it won't fail, but many in which it will. The author is aware of this since he fixes the claim toward the end: > To clarify, the surprising behaviour malloc has does not mean we should ignore its return value. We just need to be careful because malloc returning successfully does not always mean that we can use the requested memory. It…
> It's worth pointing out that if you turn overcommit off ... you will, in fact, get this guarantee But many Linux applications assume the overcommit behavior. Its far easier to just "go with the flow" or "When in Rome...". Overcommit is the programming culture of Linux and should be assumed when writing Linux apps.
Re: Malloc Never Fails (2012)
#88Earlier quoted context omitted.
Very relevant, because containers are often under what basically is ulimit. Not that you can do much when malloc fails...
If you take a look at the Linux kernel, a hugely complex and sophisticated piece of software, you'll find that it gracefully handles allocation failures.
Re: Malloc Never Fails (2012)
#89Earlier quoted context omitted.
I think that would ultimately have undesirable consequences. If this were an option on a malloc call, any such call would have to reserve the allocated memory at that point, reducing the usefulness of overcommit for other processes. This would set up a 'tragedy of the commons' scenario, where every application developer defensively uses this feature because other applications are using it.
It's already quite easy to implement manually though, just do a write after allocation.
Re: Malloc Never Fails (2012)
#90The title here is just blatantly false; there are certainly some scenarios in which it won't fail, but many in which it will. The author is aware of this since he fixes the claim toward the end: > To clarify, the surprising behaviour malloc has does not mean we should ignore its return value. We just need to be careful because malloc returning successfully does not always mean that we can use the requested memory. It…
It's a shame that turning off overcommit is done at the system level, rather than the malloc call level. Some applications, and perhaps some allocations within otherwise naive applications, might prefer to have an allocation fail early, where failure could be sensibly handled.
I discovered this because of differences in how jemalloc and my system allocator (from glibc) allocated memory. Namely, jemalloc would pass the MAP_NORESERVE option, which meant my program behaved as if overcommit was always enabled. Thus, an out-of-memory condition meant that it was subject to the OOM killer. But when I used my system's allocator, the MAP_NORESERVE option was not passed, which led to the heuristic detecting an out-of-memory condition and causing the malloc call to fail.
For more info, see `man 5 proc` and/or my exploration here: https://github.com/BurntSushi/ripgrep/issues/993#issuecommen...
(It's all still a bit wishy washy, so I think your point still stands. But I figured I'd chime in with some bits that don't appear to be widely known, and which led to some surprising differences in behavior based on which allocator one chooses.)