15 ms·
Plus, of course, a lot of modern systems use memory overcommit --- if you ask the OS for memory, it gives you uninitialised address space, and it only allocates
by david-given 11y ago
Plus, of course, a lot of modern systems use memory overcommit --- if you ask the OS for memory, it gives you uninitialised address space, and it only allocates pages of physical RAM the first time you touch each page of address space.
This has two effects:
(a) malloc() never returns NULL. It always returns a valid address, even though your system may have out of memory.
(b) by the time the kernel finds out that it's run out of physical pages, your process is already trying to use that memory... which means there's no way for your process to cope gracefully. You have to trust the kernel to do the right thing (either to scavenge a page from elsewhere, or to kill a process to make space). If you're very lucky, it'll send you a SIGSEGV...
- kbart 11y agoHm, do you have any test/references on that? I always thought that in such cases system simply swaps memory to free some RAM.
- amadvance 11y agoGoogle for Linux OOM Killer (Out Of Memory Killer). It's really annoying, your application may get killed without any way to react, even to just print a "Low memory" error.
- feld 11y agoThe entire concept of the Linux OOM Killer is asinine
- andreasvc 11y agoIt is a well known design feature (I would call it a flaw) of Unix/Linux which makes forking processes with copy-on-write memory possible. You can run out of both physical memory and swap space. Or your system is swapping is so heavily that, for all practical purposes, the system becomes unusable.
- nickpsecurity 11y agoProbably one of the best examples of my claim that UNIX has bad architecture. A well-designed system will either prevent or catch this sort of thing with apps able to detect and/or recover from it without geniuses writing them. Then, there's UNIX/Linux... I should probably add this to my list of non-security reasons (or an angle at least) for using Nizza-style architecture [1] where critical functionality is taken out of Linux part to run on microkernel or small runtime. Maybe even potential to go further and have such apps that monitor for this sort of thing with a signal to apps that works across platforms. Not just this design flaw, but potentially others where app doesn't have necessary visibility. What you think? [1] http://genode-labs.com/publications/nizza-2005.pdf http://genode-labs.com/publications/nizza-2005.pdf
- TimJYoung 11y agoComing from a Windows viewpoint, I would have thought the same thing. AFAIK, under Windows you just end up hitting the system swap file. Of course, you can start getting into a situation where physical memory is so low that everything grinds to a (ahem, virtual) halt....
- caf 11y agoYes, that's the first response. "running out of physical pages" here in the GP really means "running out of free or reclaimable pages and running out of swap".
- merijnv 11y ago> (a) malloc() never returns NULL. It always returns a valid address, even though your system may have out of memory. This is only true on Linux, for example, FreeBSD by default has partial overcommit and WILL start returning null after overcommitting some percentage of memory (I think 30% or so by default)
- ekimekim 11y agoMost major linux distros default to "heuristic overcommit", aka vm.overcommit_memory=0. The intent being to refuse obviously excessive allocations without sticking to a strict limit. You can also enable behaviour like you describe by setting overcommit_memory=2 and some ratio overcommit_ratio (default 50) or exact number of kbytes overcommit_kbytes Source: https://www.kernel.org/doc/Documentation/vm/overcommit-accounting https://www.kernel.org/doc/Documentation/vm/overcommit-accou... https://www.kernel.org/doc/Documentation/sysctl/vm.txt https://www.kernel.org/doc/Documentation/sysctl/vm.txt
- deleted 11y ago[deleted]
- amelius 11y ago> (a) malloc() never returns NULL. It always returns a valid address, even though your system may have out of memory. Unless of course you run out of virtual address space.
- zAy0LfpBZLC8mAC 11y agoIt should be noted though that (a) this behaviour is configurable, and (b) it's not actually true. If you malloc() so much memory that it cannot possibly be provided, Linux will return a failure, even in overcommit mode.
- jstanley 11y ago> (a) malloc() never returns NULL. This is not always true. For example, you can use ulimit to set an upper bound on the amount of address space the process can consume. Also, on a 32-bit system it is easy to imagine a process trying to allocate over 4G of memory and running out of address space.
- dfox 11y agoWith overcommit you will only get NULL from malloc() when you run out of the address space (or from the subset of address space that is used by malloc). When you overrun the address space ulimit, you are killed by some signal.
- jstanley 11y agoThat's not right: http://pastebin.com/aA7dasDx http://pastebin.com/aA7dasDx jes@themisto:~$ cc -o alloc alloc.c jes@themisto:~$ ulimit -v 100000 jes@themisto:~$ ./alloc malloc returned NULL after allocated 94227K EDIT: Ubuntu 15.04, x86_64, Linux 3.19
- felixgallo 11y agohowever, ulimit will only affect your process; if other processes consume enough RAM, you can still run out of pages while under the influence of ulimit.
- dfox 11y agoOK, mmap() will fail and thus malloc() will return NULL. The point is that you cannot rely on that. For example try what will happen with recursive functions that call alloca(1024).
- Patient0 11y agoSorry how is this relevant to heap allocation? alloca just allocates memory off the stack - it's literally just bumping the stack register by the number of bytes you requested (and hence it's freed when the stack pointer is reset on returning from the function call). Alloca should fail when your current thread runs out of stack space - which will generally be only a few megabytes. The total stack for a new thread is allocated from the heap at its creation, not during its execution and certainly not as part of a call to alloca.
- joosters 11y agoAs other people are commenting, malloc can still return NULL, but the critical point here is that even if you handle the NULL cases, you will still miss the other situations where your process runs out of memory. In short, if the OS over-commits RAM, it is impossible for a program to safely handle out of memory situations. One reason why overcommit is popular is because of fork(). Imagine a process that does malloc(lots of memory), then forks and execs a tiny program (/bin/true or something like it). If the fork() call succeeds, this means the OS has guaranteed that all the memory in the child process is available to be written over. i.e. it has had to allocate 'lots of memory' x 2 in total, even if only 'lots of memory' x 1 will actually be used. Without overcommit, fork() can fail even if the system won't ever use anywhere close to the limit of RAM+swap space.
- JoeAltmaier 11y agoI with you on the no-point-checking-for-malloc-fail issue. It has to be done in every place, or it rarely is effective. My old colleage Mike Rowe used to call it "Putting an altimeter on your car. So if you drive over a cliff, you can see how far it is to the ground."
- joosters 11y agoDefinitely. In practice, it's impossible to do correctly. Even if your own code gets every malloc() correct (and also properly checks the return code of every syscall and library call that might fail due to lack of memory), you still have to trust that every library you use is also perfectly written and handles its memory failures just as perfectly. It'll never happen.
- JoeAltmaier 11y agoThere's just one place that it makes sense: for very large buffers. If they fail, it doesn't mean the system is doomed. So it doesn't hurt to check that video-frame buffer alloc, or that file-decompression buffer. But for any of the small change (anything within orders of magnitude of the mean allocation size) its pointless.
- 11y ago
- kazinator 11y agoLinux can easily be configured not to do that. Then malloc returns null, when the underlying mmap nicely fails, and this can happen when the address space is nowhere near exhausted.