skip to content

How do you size the CPU, memory and disk Docker Desktop's Linux VM is allowed to use?

level: seniorimportance: should knowfreq 41%

answer

  1. The laptop's RAM is not the limit
  2. Ask what the VM was given
  3. The killer runs inside the VM
  4. Different backends, different settings file
  5. Freed space may stay inside the disk image

basics

~20 s

Every container's ceiling is the VM's, not the laptop's. On macOS the CPU, memory, swap and virtual-disk limits come from Docker Desktop's resource settings; with the Windows WSL 2 backend they come from the .wslconfig file, because the memory belongs to WSL.

solid answer

~50 s

Containers under Desktop are limited twice: by anything you pass to `docker run`, and above that by whatever the VM itself was given. `docker info` and `docker stats` report the VM's totals, not your machine's, so a container with no `--memory` flag still cannot exceed the VM budget — when it tries, the VM's kernel OOM-kills it and you see a SIGKILL exit (137) with no useful application log. That is the classic "builds fine on the 32 GiB CI runner, dies on my laptop" report. On macOS you raise the budget in Desktop's resource settings; with the WSL 2 backend those sliders do not apply, because WSL owns the VM, and you set `memory`, `processors` and `swap` in `%UserProfile%\.wslconfig` and restart WSL. Size with headroom: an oversized VM makes the whole laptop swap, and the VM's virtual disk grows on the host without shrinking when you prune.

code

bash · 3 lines
bash
docker info --format 'cpus={{.NCPU}} mem={{.MemTotal}}'
docker run --rm --memory 512m alpine sh -c 'cat /sys/fs/cgroup/memory.max'
docker inspect -f '{{.State.OOMKilled}} {{.State.ExitCode}}' digest-build

go deeper

for a junior

Know that Docker Desktop's VM has its own CPU and memory allowance, that it is a setting you can change, and that a container cannot exceed it however much RAM the laptop has.

for a middle

Explain the two ceilings — per-container cgroup limits inside, VM allocation outside — and know that docker info and docker stats report the VM, plus where the setting lives on each backend.

for a senior

Show the diagnosis end to end: an unexplained death, exit 137 with OOMKilled: true, the VM ceiling compared against observed peak usage, and a considered fix rather than reflexively dragging the memory slider to maximum.

for a principal

Own the policy: define a documented minimum local allocation, decide which workloads are simply not laptop-shaped and belong in CI or a remote environment, and make sure resource-related local failures are recognisable rather than mistaken for product bugs.

### Two ceilings, not one On a Linux server there is one ceiling: the machine, narrowed by whatever cgroup limits the container was given. On Docker Desktop there are two. The inner one is per-container (`--memory`, `--cpus`), enforced by cgroups in the VM's kernel exactly as on Linux. The outer one is the VM: the CPU count, memory and swap the virtual machine was created with, plus the size of its virtual disk. No `docker run` flag can lift the outer ceiling, and nothing about the laptop's 36 GiB of RAM matters if the VM was given 5.5. The first thing to internalise is that the engine reports the inner world. `docker info` shows CPUs and Total Memory for the VM. `docker stats` shows a MEM USAGE / LIMIT column whose limit, for an unconstrained container, is the VM's memory. A container that reads `/proc/meminfo` sees the VM. Every number you can get from inside is about the VM, so "the container says it has 5.4 GiB" tells you the VM's size, not your machine's. ### The symptom this produces A C++ email-digest builder is compiled in a container. On the Linux CI runner the build completes in a few minutes. On a developer's MacBook the same build dies at around the 11-minute mark with no compiler error — the process is simply gone, the container exits with status 137, and `docker inspect` shows `OOMKilled: true` in the container's state. 137 is 128 plus signal 9: the VM's kernel out-of-memory killer chose the largest consumer, which was a linker resolving symbols across a pile of runtime shared libraries, and killed it. Nothing in the build log says anything, because SIGKILL is not catchable and there is no chance to flush a message. The diagnosis is to compare the VM's memory against what the build peaks at: `docker info` for the ceiling, `docker stats` while it runs, and `OOMKilled` in the exit state to confirm the killer rather than a crash. The fixes are the obvious pair — give the VM more memory, or make the build need less (fewer parallel jobs, a lower linker memory profile) — and the choice depends on whether other developers have smaller laptops. ### Where the settings live **macOS.** Desktop's resource settings expose CPU count, memory, swap and a virtual-disk size limit. Changing them restarts the VM, which stops all running containers, so it is a deliberate action rather than something to do mid-incident. **Windows, WSL 2 backend.** Desktop does not own the VM; WSL does, and the resource sliders are absent or inert. The knobs are in `%UserProfile%\.wslconfig` under a `[wsl2]` section — `memory`, `processors`, `swap` — and they apply after `wsl --shutdown` and a restart. WSL also claims memory lazily and has historically been slow to hand it back to Windows, which is why the WSL VM process can appear to hoard RAM long after a build finished; newer WSL versions offer a memory-reclaim option to mitigate that. **Windows, Hyper-V backend.** Where Desktop runs its own VM instead of using WSL, the sliders apply as on macOS. ### Sizing judgement Bigger is not better. The VM's memory is taken from the same laptop that is running an IDE, a browser with forty tabs and a video call; over-allocating produces host-level swapping, which is far worse than a container that occasionally has to run with fewer parallel jobs. A reasonable approach is to size for the largest routine workload — usually a build or a Compose stack of several services — leave several gigabytes for the host, and treat a one-off giant job as a reason to run it in CI rather than a reason to permanently resize. CPU allocation follows the same logic: giving the VM every core makes the machine unresponsive while a build runs, and build parallelism inside the container should be set to match what the VM actually has, not what the laptop has, or the compiler oversubscribes and thrashes. ### Disk, and why pruning does not give the space back Images, containers and named volumes live inside the VM, in a virtual disk file on the host. That file is sparse: it grows as the VM writes and, historically, does not shrink when data inside is deleted. So `docker system df` can show that a prune reclaimed several gigabytes while the host's free space is unchanged. Reclaiming host space needs the disk image itself to be shrunk or reset — Desktop exposes a way to do this, and newer versions do better at returning trimmed space automatically. Two consequences worth stating: the virtual-disk size limit is a real ceiling that produces "no space left on device" inside containers while the laptop still shows free space, and a laptop that is genuinely full will not be rescued by pruning alone. ### The interview-shaped summary Name the two ceilings, say where each is configured on each backend, name the symptom (a SIGKILL exit and `OOMKilled: true` rather than an application error), and finish with the judgement: size the VM for the routine workload with host headroom, and push the outlier job to a machine built for it.

  • How do you confirm a container was OOM-killed rather than crashing on its own?
    Check the container's state: `docker inspect -f '{{.State.OOMKilled}} {{.State.ExitCode}}'` returns `true 137` when the VM's kernel killed it. Exit 137 is 128 plus SIGKILL, and because SIGKILL cannot be handled there is no application-level log — an empty tail of the log with a non-zero exit is itself a hint. A crash of the process's own making usually leaves a stack trace and a different exit code.
  • A colleague says their Mac is out of disk but `docker system df` shows very little in use. What is happening?
    Space freed inside the VM does not automatically shrink the virtual disk file on the host, so the file keeps its high-water mark. Pruning reclaims space for future container use but the host sees no change until the disk image is trimmed or reset through Desktop. It is also worth checking whether the VM's disk-size limit is the real problem, which shows up as 'no space left on device' inside containers while the laptop still reports free space.
  • Should the team standardise the VM size across developer laptops?
    Standardise a documented minimum rather than an exact figure: laptops differ, and a fixed allocation that fits a 64 GiB machine will cripple a 16 GiB one. Say what the routine local stack needs, note the settings location for each backend, and route the genuinely large jobs to CI so nobody's local environment has to be sized for the worst case.

saying these in an interview costs you the question

  • Assumes the container can use all the laptop's RAM
  • Reads docker info numbers as the host machine's
  • Adds --memory expecting to raise the ceiling
  • Treats exit 137 as an application bug
  • Allocates every core and all memory to the VM
  • Expects pruning to free host disk space

context