How can I allocate memory on Linux without overcommitting, so that malloc actually returns NULL
if no memory is available and the process doesn't randomly crash on access?
My understanding of how malloc works:
- The allocator checks the freelist if there is free memory. If yes, the memory is allocated.
- If no, new pages are allocated from the kernel. This would be where overcommit can happen. Then the new memory is returned.
So if there is a way to get memory from the kernel that is immediately backed by physical memory, the allocator could use that instead of getting overcommitted pages, and return NULL
if the kernel refuses to give more memory.
Is there a way this can be done?
Update:
I understand that this cannot fully protect the process from the OOM killer because it will still be killed in an out of memory situation if it has a bad score, but that is not what I'm worried about.
Update 2:
Nominal Animal's comment gave me the following idea of using mlock
:
void *malloc_without_overcommit(size_t size) {
void *pointer = malloc(size);
if (pointer == NULL) {
return NULL;
}
if (mlock(pointer, size) != 0) {
free(pointer);
return NULL;
}
return pointer;
}
But this is probably quite slow because of all the system calls, so this should probably be done at the level of the allocator implementation. And also it prevents making use of swap.
Update 3:
New idea, following John Bollingers's comments:
- Check if enough memory is available. From what I understand this has to be checked in
/proc/meminfo
in theMemFree
andSwapFree
values. - Only if enough space is available (plus an additional safety margin), allocate the memory.
- Find out the pagesize with
getpagesize
and write one byte to the memory every pagesize, so that it gets backed by physical memory (either RAM or swap).
I also looked more closely at mmap(2) and found the following:
MAP_NORESERVE
Do not reserve swap space for this mapping. When swap space is reserved, one has the guarantee that it is possible to modify the mapping. When swap space is not reserved one might get SIGSEGV upon a write if no physical memory is available. See also the discussion of the file /proc/sys/vm/overcommit_memory in proc(5). In kernels before 2.6, this flag only had effect for private writable
Does this imply that mmaping with ~MAP_NORESERVE
will completely protect the process from the OOM killer? If so, this would be the perfect solution, as long as there is a malloc
implementation, that can work directly on top of mmap
. (maybe jemalloc?)
Update 4:
My current understanding is that ~MAP_NORESERVE
will not protect against the OOM killer but at least against segfaulting on first write to the memory.