As a guide from How-To Geek by Arol Wright points out, that convenience comes attached to a very hungry default. When you launch a container with a standard docker run command, Docker places zero restrictions on how much memory or processor time that container can claim. Unless you explicitly fence it in, any container is free to consume as much RAM and CPU capacity as the host kernel scheduler will hand over. For Windows developers and IT administrators running Docker Desktop alongside Windows Subsystem for Linux 2 (WSL 2), understanding the boundary between individual container limits and virtual machine ceilings is the difference between a responsive workstation and a laptop whose cooling fans sound ready for liftoff.
Why Unbounded Containers Become Silent Resource Hogs
The Default Behavior: An Open Buffet for Processes
According to Docker’s official engine documentation, containers start with no resource constraints by default. That design makes total sense when you are testing a hello-world container or running a quick build step where you want maximum throughput without fiddling with resource calculator flags. It becomes a real liability, however, when "disposable" containers quietly turn into permanent background residents.
Think about how many times you have spun up a local microservice stack or a self-hosted tool, finished testing, and simply closed PowerShell or Windows Terminal. A detached container does not stop just because your terminal session ended. It stays alive in the background, holding onto allocated memory and waking the processor every time an internal cron job, polling loop, or health check fires.
One idle container sipping a few hundred megabytes of RAM rarely sets off alarm bells. Five or six forgotten test stacks, or a single buggy Node.js or Python service with a slow memory leak, will eventually corner your system's physical memory.
What Happens When Memory Runs Out?
When a Linux environment runs out of available memory to perform critical system functions, the Linux kernel triggers an Out Of Memory Exception (OOME) and unleashes its Out-Of-Memory (OOM) killer to start terminating processes and freeing pages.
The catch? Without explicit container boundaries, the kernel’s OOM killer does not necessarily know which forgotten test container is the real culprit. It evaluates processes across the environment and can just as easily terminate a vital database, an active SSH session, or the Docker daemon itself.
The Windows 11 and WSL 2 Factor: vmmem at the Top of Task Manager
On Windows and macOS, the architecture adds another layer to the puzzle. Because Linux containers require a Linux kernel, Docker Desktop runs them inside a lightweight virtual machine. On modern Windows 10 and Windows 11 systems using the WSL 2 backend, that environment shares the Linux utility VM managed by Windows, which shows up in Task Manager as vmmem or vmmemWSL.
Docker’s WSL documentation notes that WSL 2 uses dynamic memory allocation, requesting CPU and RAM from Windows as workloads demand it. However, as Windows developers frequently discover—and as How-To Geek highlights—Linux page caching and runaway container allocations inside that utility VM can cause vmmem to hold onto gigabytes of host RAM even after heavy tasks wind down. Because Docker never prompts you to set a ceiling when you launch a container, and never pops up a toast notification reminding you that a test database has been running for three months straight, the only visible clue is a sluggish PC.
Section Summary:
- Docker containers launch with unlimited access to host CPU and RAM by default.
- Forgotten background containers and memory leaks can trigger the Linux kernel's OOM killer.
- On Windows, unconstrained containers running inside the WSL 2 backend drive up memory consumption under the
vmmemprocess, impacting host performance.
How to Diagnose What Is Actually Eating Your RAM
Before slapping arbitrary memory caps onto every container you own, take five minutes to inspect what is actually running and what it genuinely needs. Setting a limit too low will just starve your workload and cause constant crashes.
Step 1: Audit Running Containers
Open PowerShell, Command Prompt, or your WSL terminal and list active containers:
docker ps
If you spot forgotten containers from last month's weekend project, stop them immediately with docker stop <container_name_or_id>.
Step 2: Watch Live Resource Consumption
To see how much hardware your active containers are claiming in real time, run:
docker stats
Docker’s CLI reference explains that docker stats streams live telemetry for CPU percentage, memory consumption against configured limits, network I/O, block I/O, and active process counts (PIDS). Let this run while you exercise your application over a few days so you can observe its normal baseline and peak spikes.
Expert Note on Linux Memory Reporting: According to Docker’s stats documentation, on Linux engines the CLI subtracts page cache usage from total memory to give you a clearer picture of active working memory, whereas raw API calls report total memory and cache separately. Always leave healthy headroom above the peak number you see in docker stats so normal traffic spikes do not push the container over a cliff.
Fencing In Individual Containers: CLI Flags and Compose
Once you know what a service requires, you can enforce boundaries either at launch time via the command line or declaratively in Docker Compose.
| Control Target | docker run Flag | compose.yaml (deploy.resources) | What It Actually Does |
|---|---|---|---|
| Hard Memory Cap | --memory="512m" (or -m) | limits.memory: 512M | Sets the strict upper ceiling of RAM the container may use (minimum allowed is 6 MB). |
| Soft Memory Limit | --memory-reservation="256m" | reservations.memory: 256M | Activates only when the host detects memory contention or low-memory pressure. |
| CPU Time Cap | --cpus="1.5" | limits.cpus: '1.5' | Caps processor time (e.g., 1.5 equals at most one and a half CPU cores' worth of processing time). |
| Process Limit | --pids-limit=100 | limits.pids: 100 | Prevents fork bombs or runaway bugs from spawning endless child processes. |
Using docker run Flags
To cap a container at 512 megabytes of RAM and 1.5 CPUs, pass the flags directly when creating the container:
docker run -d --name my-api --memory="512m" --memory-reservation="256m" --cpus="1.5" --pids-limit=100 my-api-image:latest
Important Nuance on Hard Memory Limits: How-To Geek notes that exceeding a memory ceiling causes Docker to stop the container rather than dragging down the host. More precisely, Docker’s resource constraints documentation specifies that when a container hits its hard --memory limit, the Linux kernel triggers an OOM event scoped to that container and kills processes inside the container. If the killed process happens to be PID 1 (the main entrypoint process), the container exits; if it is a worker child process, the container might stay up in a degraded or broken state. Never disable the OOM killer (--oom-kill-disable) on a container without setting a -m memory limit, or a runaway process will once again threaten the entire host.
Using Docker Compose
Hardcoding CLI flags relies on human memory, which is notoriously unreliable on a Friday afternoon. Putting resource limits inside your compose.yaml file ensures every developer on your team gets the exact same guardrails:
services:
app:
image: my-api-image:latest
mem_limit: 512m
deploy:
resources:
limits:
cpus: '1.50'
memory: 512M
pids: 100
reservations:
memory: 256M
Compatibility Check: While modern Docker Compose releases read the deploy.resources block during standard docker compose up runs without requiring a full Docker Swarm cluster, Docker’s official Compose Deploy Specification notes that the deploy section is formally optional for Compose implementations—meaning an implementation that does not support it will silently ignore the block without throwing a syntax error. If you also use the top-level service key mem_limit, Docker’s specification requires it to match deploy.resources.limits.memory. After launching a stack, always run docker stats to verify that the LIMIT column reflects your intended cap rather than the total RAM of your VM.
Controlling the Windows Host: Docker Desktop and .wslconfig
Capping individual containers stops a single rogue app from starving your other containers, but Windows users also need to control how much host RAM the underlying Linux VM is allowed to claim from Windows 11 or Windows 10.
1. Docker Desktop Settings and Resource Saver Mode
If you use the traditional Hyper-V backend, you can adjust CPU, RAM, and virtual disk ceilings directly in Docker Desktop under Settings > Resources.
Regardless of backend, check that Docker Desktop's Resource Saver mode is enabled in Settings. According to Docker’s documentation, when no containers are running, Resource Saver mode automatically powers down the underlying Linux VM after an idle period, saving 2 GB or more of host RAM. (Just remember: if a single forgotten container is still ticking away in the background, Docker is not idle, and Resource Saver will never kick in!)
2. Capping WSL 2 Globally with .wslconfig
When Docker Desktop runs on the WSL 2 backend, global VM memory and CPU limits are governed by Windows Subsystem for Linux rather than Docker Desktop’s sliders. According to Microsoft Learn’s WSL configuration documentation, you can cap the entire WSL 2 utility VM by creating a .wslconfig file inside your Windows user profile folder (%UserProfile%\.wslconfig, which expands to C:\Users\<YourUsername>\.wslconfig).
This file does not exist by default. Open Notepad or VS Code, create %UserProfile%\.wslconfig, and add a [wsl2] block tailored to your PC's hardware:
[wsl2]
memory=4GB
processors=2
Note: Microsoft Learn uses 4GB and 2 processors as sample syntax—not a one-size-fits-all rule. If you have a 32 GB workstation running heavy local Kubernetes clusters, 4 GB will be far too tight; if you are on a 16 GB ultrabook running two small containers, 4 GB to 6 GB is often plenty. Remember that .wslconfig governs all WSL 2 Linux distributions running on your PC, not just Docker.
For your changes to take effect, Microsoft’s documentation notes that you must completely stop the WSL subsystem (waiting at least 8 seconds after closing all shells, or forcing an immediate shutdown). Open PowerShell and run:
wsl --shutdown
When you restart Docker Desktop or open your Linux shell, WSL 2 will boot with your new memory ceiling strictly enforced.
Taming the Other Silent Defaults: Logs, Restart Loops, and Disk Bloat
Memory and CPU aren't the only areas where Docker prioritizes out-of-the-box convenience over long-term system hygiene. Arol Wright’s report highlights four operational habits that prevent your storage drive and processor from getting chewed up over time:
1. Enable Log Rotation (json-file)
Docker’s default json-file logging driver does not rotate logs (max-size defaults to -1, meaning unlimited). A noisy container outputting debug traces around the clock can quietly write a single JSON log file until it eats tens of gigabytes of SSD space.
You can cap logs per container using --log-opt max-size=10m --log-opt max-file=3, or configure it globally for all newly created containers in your Docker Engine daemon.json config (accessible in Docker Desktop under Settings > Docker Engine):
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
(Per Docker’s logging documentation, values inside log-opts in daemon.json must be enclosed in quotes as strings, and changes only apply to newly created containers, not existing ones.)
2. Ditch restart: always for Smarter Policies
Setting a container to --restart always means two things happen: if you manually stop the container and later reboot your Windows PC, Docker starts that container right back up; and if the container has a fatal configuration error, it will crash-loop infinitely, spiking your CPU as it restarts forever.
- Use
unless-stoppedfor persistent services so Docker respects your manualdocker stopcommands across host reboots. - Use
on-failure:5(with a maximum retry count) for batch jobs or tricky services so a broken container gives up after five consecutive crashes instead of burning CPU indefinitely.
3. Relax Aggressive Health Checks and Slim Down Images
If a container defines a HEALTHCHECK that spins up a shell script, curls an endpoint, or queries a database every 2 or 3 seconds, that container will never let your CPU rest. Stretching the health check interval to 30s or 60s is plenty for almost any local or home-server workload and drastically reduces background wakeups. Similarly, choosing -slim or -alpine base images cuts down disk footprint and tends to ship with fewer unnecessary background daemons.
4. Prune Unused Artifacts—Carefully
Over weeks of building and testing, stopped containers, dangling image layers, unused virtual networks, and build caches pile up. Running a periodic cleanup reclaims that disk space:
docker system prune
Data Safety Warning on Volumes: How-To Geek mentions adding the --volumes flag to clear out orphaned volumes. Be extremely careful here: Docker’s CLI documentation warns that while docker system prune leaves volumes untouched by default to protect persistent data, passing docker system prune --volumes permanently deletes all unused anonymous volumes (and depending on your Docker version and flags, unused volumes not attached to at least one container). If you stopped your local database container five minutes ago for maintenance and run a volume prune, your database tables will vanish into the ether. Always inspect docker volume ls and back up critical data before pruning volumes.
Section Summary:
- Cap global WSL 2 memory on Windows using
%UserProfile%\.wslconfigfollowed bywsl --shutdown. - Configure
max-sizeandmax-fileon thejson-filelog driver so chatty containers don't fill your SSD. - Prefer
unless-stoppedoron-failureoveralwaysfor restart policies, and back up persistent data before runningdocker system prune.
By pairing per-container memory and CPU limits with a sensible .wslconfig ceiling on Windows, you get all the rapid-fire convenience of Docker without handing a blank check for your PC's hardware to a container you forgot about two months ago.
References
- Docker's hidden default is draining your system memory, here's the fix How-To Geek · 2026-10-17T17:30:17+00:00
- Resource constraints | Docker Docs docs.docker.com
- Docker on Windows is eating your RAM: here's how to fix it | Rostand MIGAN rostand.dev