The shared memory device, /dev/shm
, provides a temporary file storage filesystem using RAM for storing files. It’s not mandatory to have /dev/shm
, although it’s probably desirable since it facilitates inter-process communication (IPC).
Why would you use /dev/shm
instead of just stashing a temporary file under /tmp
? Well, /dev/shm
exists in RAM (so it’s fast), whereas /tmp
resides on disk (so it’s relatively slow).
BASH Demo
You can create temporary files in shared memory directly from BASH. First let’s check what’s currently under /dev/shm
.
ls -l /dev/shm
total 0
Nothing. Cool, we’ll write the current date and time to a file under /dev/shm
.
date >/dev/shm/date.txt
Check if the file is there.
ls -l /dev/shm/
-rw-rw-r-- 1 wookie wookie 29 Nov 8 05:40 date.txt
Indeed it is. The file can then be accessed from another process.
cat /dev/shm/date.txt
Mon 08 Nov 2021 05:40:20 GMT
So the shared memory behaves just like a normal file system, but it’s all in RAM.
A shared memory segment is a chunk of memory that is shared between multiple processes.
Many applications make use of shared memory. We can delve into this using the ipcs
command. We’ll start by looking at the shared memory segments.
ipcs -m
------ Shared Memory Segments --------key shmid owner perms bytes nattch status 0x00000000 1376256 wookie 600 7802880 2 dest 0x00000000 1277954 wookie 600 851968 2 dest 0x00000000 1277956 wookie 600 851968 2 dest 0x00000000 1277958 wookie 600 77824 2 dest 0x00000000 1671189 wookie 600 36864 2 dest 0x00000000 1179651 wookie 600 8011776 2 dest 0x00000000 1703959 wookie 600 524288 2 dest0x0001eaea 557069 wookie 666 16384 0
There are six shared memory segments of various sizes. They have permissions of either 600 (read and write for user) or 666 (read and write for user, group and other). How do those segments relate to processes?
ipcs -pm
------ Shared Memory Creator/Last-op PIDs --------shmid owner cpid lpid 1376256 wookie 268958 1923 1277954 wookie 6254 2858241277956 wookie 6254 285824 1277958 wookie 6254 285824 1671189 wookie 6139 504020 1179651 wookie 24234 285810 1703959 wookie 282127 479099 557069 wookie 125674 125674
The cpid
column gives the PID of the process that created the shared memory segment, while the lpid
column reflects the PID of the last process which interacted with it.
Those shared memory segments were created by four distinct processes. If we look up the PIDs this is what we find:
268958 /usr/lib/rstudio/bin/rstudio 6254 /usr/lib/firefox/firefox 6139 /opt/google/chrome/chrome 24234 /usr/lib/thunderbird/thunderbird 282127 /usr/lib/slack/slack 125674 /usr/share/dbeaver-ce/dbeaver
Many desktop applications (for example, Slack, Firefox, RStudio, Thunderbird and DBeaver) use shared memory. Some applications (like Firefox) use multiple segments of shared memory.
Now it stands to reason that if these applications are using shared memory on my desktop then they will probably want to use it in a Docker container too. So we need to ensure that there is shared memory available in a container.
What about Docker?
Docker containers are allocated 64 MB of shared memory by default. We’ll fire up an Ubuntu container to test.
docker run --rm -it --name ubuntu ubuntu
Now we can check the characteristics of that container using docker inspect
.
docker inspect ubuntu | grep -i shm
"ShmSize": 67108864,
Nice: 64 MB is precisely 67108864 bytes!
Can we change the amount of shared memory allocated to a container? Sure we can! Use the --shm-size
option.
docker run --rm -it --name ubuntu --shm-size=2gb ubuntu
Inspect the container again.
docker inspect ubuntu | grep -i shm
"ShmSize": 2147483648,
Aha: 2 GB is exactly 2147483648 bytes.
In both of the cases above the container is getting its own /dev/shm
, separate from that of the host. To confirm, let’s check on its contents.
ls -l /dev/shm
total 0
It’s pristine: no sight of the file we created in /dev/shm
on the host.
Mounting Host /dev/shm
in a Container
What about sharing memory between the host and a container or between containers? This can be done by mounting /dev/shm
.
docker run --rm -it --name ubuntu -v /dev/shm:/dev/shm ubuntu
Now we can see the file we created earlier from within the container.
cat /dev/shm/date.txt
Mon 08 Nov 2021 05:40:20 GMT
I make rather extensive use of Selenium Docker images. For anything but simple applications these have a tendency to be rather memory intensive.
Launch Selenium/Firefox and allow access to 2 GB of shared memory.
docker run -d -p 4444:4444 --shm-size=2gb selenium/standalone-firefox:3.141
Launch Selenium/Chrome and volume mount the host’s shared memory.
docker run -d -p 4444:4444 -v /dev/shm:/dev/shm selenium/standalone-chome:3.141
Chrome can be particularly resource hungry, so I often disable its use of shared memory via the --disable-dev-shm-usage
option.
from selenium import webdriverfrom selenium.webdriver.common.desired_capabilities import DesiredCapabilitiesfrom selenium.webdriver.chrome.options import Optionsoptions = Options()options.add_argument("--disable-dev-shm-usage")driver = webdriver.Remote( command_executor="http://127.0.0.1:4444/wd/hub", desired_capabilities=DesiredCapabilities.CHROME, options=options,)
Cleaning Up
Just to keep things neat and tidy, we’ll delete the files that we created in /dev/shm
.
rm /dev/shm/date.txt