Troubleshooting Docker Container Exit Code 137 (OOM Killed) in Windows WSL2 Ubuntu
Fix Docker container exit code 137 (OOM killed) in WSL2 Ubuntu. Diagnose and resolve out-of-memory errors by configuring WSL2 and Docker memory limits effectively.
Fix Docker container exit code 137 (OOM killed) in WSL2 Ubuntu. Diagnose and resolve out-of-memory errors by configuring WSL2 and Docker memory limits effectively.
A Docker container exiting unexpectedly with code 137 on a Windows host using WSL2 with an Ubuntu distribution is a common and often frustrating issue. This error typically indicates that your container, or the underlying WSL2 environment, has run out of memory and has been forcibly terminated by the Linux Out-Of-Memory (OOM) killer. When this happens, your application service will become unavailable, leading to downtime and requiring manual intervention to restart. Understanding the interaction between Docker Desktop, WSL2, and the Linux kernel's memory management is key to resolving this persistent problem.
Symptom & Error Signature
Users typically observe their Docker containers stopping abruptly without any explicit command, often resulting in their web application or service becoming unreachable. Upon inspecting the container's status or logs, the exit code 137 will be prominently displayed.
Typical docker ps -a output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1b2c3d4e5f6 my-app-image:latest "nginx -g 'daemon ofโฆ" 2 minutes ago Exited (137) 1 minute ago my-web-app
And examining the container logs will usually show little to no specific application error, as the process was killed externally:
docker logs a1b2c3d4e5f6
# (Potentially no specific errors, or just the last few application logs before the kill signal)
The most conclusive evidence comes from the WSL2 distribution's kernel logs, accessible via dmesg within your Ubuntu WSL2 instance:
# Inside your Ubuntu WSL2 instance
dmesg | grep -i "oom-killer"
Expected dmesg output (or similar):
[ 1234.567890] oom-kill:constraint=CONTAINER,nodemask=(null),cpuset=/,mems_cgroup=user.slice/user-1000.slice/session-2.scope/docker/a1b2c3d4e5f6.scope,task_memcg=/user.slice/user-1000.slice/session-2.scope/docker/a1b2c3d4e5f6.scope,task=node,pid=12345,uid=0
[ 1234.567890] Memory cgroup out of memory: Killed process 12345 (node) total-vm:4500000kB, anon-rss:3800000kB, file-rss:0kB, shmem-rss:0kB, UID:0 pgtables:8765kB oom_score_adj:0
[ 1234.567890] oom_reaper: reaped process 12345 (node), now dead
Root Cause Analysis
Exit code 137 is a standard Unix exit code indicating that a process was terminated by a SIGKILL signal (signal 9). In the context of Docker and Linux, this almost universally points to the kernel's Out-Of-Memory (OOM) killer terminating the process because the system, or the container's allocated memory, was exhausted.
Here's a breakdown of the underlying reasons:
WSL2 Global Memory Limit Exhaustion:
- Docker Desktop runs its Linux daemon within a dedicated WSL2 virtual machine. By default, WSL2 dynamically allocates memory up to a certain percentage of your host's RAM (e.g., 50% on Windows 10, or 80% on Windows 11, capped at specific amounts).
- If your Docker containers, combined with other processes running within the WSL2 instance (e.g., VS Code remote, other CLI tools), collectively exceed this default WSL2 memory limit, the Linux kernel inside the WSL2 VM will trigger its OOM killer.
- The OOM killer selects a "guilty" process (often your memory-intensive Docker container) and terminates it to free up resources, resulting in
exit code 137.
Docker Container Specific Memory Limit Exhaustion:
- Even if the overall WSL2 memory is sufficient, individual Docker containers can be configured with their own memory limits (e.g., using
-mormem_limitin Docker Compose). - If a container's application exceeds its specific allocated memory limit, the Docker daemon (which uses cgroups to enforce these limits) will again cause the Linux kernel to send a
SIGKILLto the offending process. This is a common scenario for applications with memory leaks or those that simply require more resources than initially provisioned.
- Even if the overall WSL2 memory is sufficient, individual Docker containers can be configured with their own memory limits (e.g., using
Application Memory Leaks or Inefficiency:
- The application running inside the container might have a memory leak or be inefficiently designed, gradually consuming more and more RAM until it hits a hard limit.
- Common culprits include long-running data processing jobs, complex web applications, or services with large in-memory caches that are not properly managed.
Host Resource Contention:
- While less direct for
exit code 137within WSL2, heavy memory usage by other applications on your Windows host can indirectly starve the WSL2 VM of available physical RAM, exacerbating the OOM issue.
- While less direct for
Step-by-Step Resolution
Addressing the exit code 137 OOM error requires a systematic approach, starting from the global WSL2 memory configuration down to individual container and application-level optimizations.
1. Verify the OOM Condition and Identify Culprit
Before making changes, confirm the OOM event and get insights into resource usage.
Check Docker Container Status:
docker ps -aLook for containers with
Exited (137).Review WSL2 Kernel Logs for OOM Killer: Open your Ubuntu WSL2 terminal and execute:
dmesg -T | grep -i "oom-killer" | tail -n 20This command prints recent kernel messages related to the OOM killer, often pinpointing the process (and thus likely the container) that was terminated.
Monitor Container Resource Usage: Use
docker statsto get real-time memory usage for running containers.docker statsThis helps identify which container is consuming the most memory just before a crash. You can also use
docker inspect <container_id>to view configured memory limits.
2. Adjust WSL2 Global Memory Limits
This is often the most critical step, as WSL2's default memory allocation might be insufficient for demanding Docker workloads.
This configuration applies to all WSL2 distributions. If you have other memory-intensive WSL2 instances, they will also compete for this increased memory.
Create or Edit
.wslconfig: On your Windows host, navigate to your user profile directory (C:Users<YourUsername>). Create a file named.wslconfigif it doesn't exist, or edit it if it does.# In C:Users<YourUsername>.wslconfig [wsl2] memory=8GB # Set to a value appropriate for your host system (e.g., 50% of host RAM) processors=4 # Optional: Specify the number of processorsExplanation:
memory: This sets a hard cap on the amount of RAM that the WSL2 VM (and thus Docker Desktop's engine) can consume from your Windows host. Choose a value that leaves enough RAM for your host OS and other Windows applications. A good starting point is around 50-70% of your total physical RAM, but adjust based on your host's total memory (e.g., 8GB for a 16GB system, 12-16GB for a 32GB system).processors: (Optional but recommended) Limits the number of virtual processors WSL2 can use.
Shutdown WSL2 and Restart Docker Desktop: Open a Windows PowerShell or Command Prompt as Administrator and run:
wsl --shutdownThis command will stop all running WSL2 distributions. After it completes, restart Docker Desktop from your system tray. Docker Desktop will reinitialize its WSL2 backend with the new memory limits.
3. Configure Docker Desktop WSL 2 Backend Resources
While .wslconfig sets the global WSL2 VM limits, Docker Desktop also has its own resource settings that can indirectly affect performance and stability.
Open Docker Desktop Settings: Click the Docker Desktop icon in your system tray, then navigate to
Settings(the gear icon).Navigate to Resources: Go to
Resources->WSL INTEGRATION. Ensure your Ubuntu distribution is enabled. Go toResources->Advanced. Here, you might see options for "Memory" and "Swap" used by Docker.- If
Use the recommended settingsis checked, Docker Desktop typically tries to respect the.wslconfiglimits. - If you have manually adjusted "Memory" or "Swap" here, ensure they are not set to excessively low values that could contradict your
.wslconfigsettings. In most cases, letting.wslconfigmanage the primary memory allocation for the WSL2 VM is best.
- If
4. Increase Specific Docker Container Memory Limits
If the global WSL2 memory is ample, but a particular container is still getting OOM killed, it's likely hitting its own Docker-enforced memory limit.
For
docker runcommands: Add the-m(or--memory) flag:docker run -d --name my-web-app -p 80:80 -m 2g --cpus 1 my-app-image:latestThis example limits the container to 2GB of RAM.
For
docker-compose.yml: Add themem_limitand optionallycpusunder the service definition:version: '3.8' services: web: image: my-app-image:latest container_name: my-web-app ports: - "80:80" deploy: resources: limits: memory: 2G cpus: '1.0' # 1 CPU coreIn Docker Compose v3, memory limits are specified under
deploy.resources.limits.memoryfor Swarm compatibility, but Docker Desktop also honors them for single-host deployments.After modifying
docker-compose.yml, run:docker-compose up -d --build --force-recreate
5. Optimize Application Memory Usage within the Container
While increasing limits helps, a truly robust solution often involves optimizing the application itself.
Identify Memory Hogs: Use profiling tools specific to your application's language/framework (e.g., JVM profilers for Java,
go tool pproffor Go,memory_profilerfor Python) to pinpoint memory leaks or inefficient data structures. Inside a running container, you can also usehtop(after installingapt update && apt install -y htop) orsmemto see process memory usage.Tune Application Settings:
- JVM Applications: Adjust JVM heap size settings (e.g.,
-Xmx,-Xms) to be appropriate for the container's allocated memory. Ensure they are less than the Docker container'smem_limit. - Node.js: Consider
--max-old-space-sizeif V8 is consuming too much memory. - PHP-FPM: Adjust
memory_limitinphp.iniandpm.max_childrensettings inphp-fpm.conf. - Databases: Tune buffer/cache sizes (e.g.,
innodb_buffer_pool_sizefor MySQL/MariaDB,shared_buffersfor PostgreSQL).
- JVM Applications: Adjust JVM heap size settings (e.g.,
Reduce Container Bloat: Use multi-stage builds in your Dockerfile to create smaller, more efficient final images, reducing the memory footprint of the container itself. Avoid installing unnecessary packages.
6. Monitor and Profile System Resources
Continuous monitoring is essential to detect recurring OOM issues or to catch potential memory growth before it leads to a crash.
Docker Stats & Events: Use
docker statsfor real-time overview. For historical data or event-driven alerts, consider using Docker's event stream:docker events --filter type=container --filter event=oom.WSL2 Resource Monitoring: Inside your Ubuntu WSL2 instance, use standard Linux tools like
htop,free -h, ortopto monitor the overall memory usage of the WSL2 VM.Prometheus/Grafana Integration: For more advanced setups, deploy monitoring agents like
node_exporter(in WSL2) andcadvisor(as a Docker container) to collect metrics. Visualize these metrics using Prometheus and Grafana dashboards to track memory, CPU, and disk I/O over time, helping to identify trends and predict OOM events.
By systematically applying these steps, you can effectively diagnose and resolve exit code 137 related to Out-Of-Memory errors for your Docker containers running on Windows WSL2 Ubuntu. Remember that finding the right balance of memory allocation requires understanding your application's needs and your host system's capabilities.
Our Production Verification Guarantee
Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.