linuxshared-memorymmapenomem

mmap returns ENOMEM with shm_open file object


I'm experimenting with shm_open in Linux and I'm running into problems. I'm frequently resizing a shared memory segment with ftrunc and using mmap to remap the resized segment. However, right around the 20 megabyte mark I get ENOMEM from mmap.

I have attempted the following to do to resolve the issue:

First, I found out about these sysctl parameters. I reconfigured them:

kernel.shmmax = 268435456
kernel.shmall = 2097152

(shmall is specified in pages)

The issue still occurred after this. Investigating the details of the resize that causes the issue revealed that the call made to ftrunc to resize the shared memory object succeeded (the corresponding file in /dev/shm had the requested new size).

Documentation from here suggests three possible causes for an ENOMEM errno:


[ENOMEM]
MAP_FIXED was specified, and the range [addr,addr+len) exceeds that allowed for the address space of a process; or, if MAP_FIXED was not specified and there is insufficient room in the address space to effect the mapping.

[ENOMEM]
[ML] The mapping could not be locked in memory, if required by mlockall(), because it would require more space than the system is able to supply.

[ENOMEM]
[TYM] Not enough unallocated memory resources remain in the typed memory object designated by fildes to allocate len bytes.


I am not using MAP_FIXED or locking, and the size of the image in /dev/shm suggests that the third reason is not the problem. My mmap call looks like this:

mmap(mem, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)

where mem initially is 0 and thereafter refers to the last address mmap successfully mapped.

I found information suggesting that ulimit settings could be limiting the memory mappable into a single process, but I don't think the problem was here. Just in case, ulimit -a looks like this on my machine:

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 20
file size               (blocks, -f) unlimited
pending signals                 (-i) 16382
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65536
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) unlimited
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Solution

  • I misread the documentation for mmap, which says that mmap returns a mapping based on the first parameter (the previously mapped address in my case), and the result is defined by implementation. I took this as a suggestion that mmap might remap my previous mapping for me, but this was certainly not the case. this might only have been the case if I had used the MAP_FIXED flag, but I avoided this because the documentation recommended against it.

    In any case, it was necessary to use munmap to remove the previous mapping before creating a new one.