You deploy a container, then check on it a few hours later, running docker stats out of habit. It reports 340 MiB of memory used against a 512 MiB limit. All seems fine.
A later check shows the number has risen to 410 MiB, even though traffic hasn’t budged. Is the app leaking, or is the Linux kernel keeping page cache that could be reclaimed if memory pressure spikes?
Without a way to track memory metrics over time, you are left guessing, right up until the container reaches its limit and gets OOM-killed.
That’s why monitoring Docker memory usage matters. In this guide, we’ll examine how Docker consumes memory, identify the reasons behind high usage, set predictable limits and how to monitor containers over time.
Key takeaways
- Use docker stats for a quick look at container memory usage, spotting the ones that chew up more resources than they should.
- Look beyond total memory usage. Metrics like RSS, cache, working set, swap, and memory limits give you more context when digging into memory problems.
- Set proper memory limits so one container doesn’t hog the resources other workloads need.
- Track memory over time; a slow climb could signal a leak or an inefficient job.
- Tools such as Prometheus, Grafana, and cAdvisor work well for metrics-based monitoring. If you want memory metrics, alerts, logs, and traces all in one spot, an observability platform like Middleware might be better.
- When you see OOM kills, look at memory usage, container limits, how the app behaves, and host-level pressure, rather than just bumping the limit.
What is Docker memory usage?
Docker memory usage is the amount of system memory a running container consumes from the host. It includes memory used by application processes, filesystem cache, shared memory, and other resources associated with the container.
Docker containers run as isolated processes on a host, but they still use the host’s CPU and memory. Docker Engine uses Linux kernel features, including control groups (cgroups), to track and control these resources. For a deeper look at how those signals map onto CPU, memory, and network usage across your whole fleet, see our guide to container monitoring.
A container’s memory usage can change as its workload changes. An application that handles more requests may allocate more memory, while the Linux kernel may also use available memory for filesystem caching. This is why a high memory value does not always indicate a memory leak or an application problem.
How Docker manages memory using cgroups
For example, you can limit a container to 512 MiB:
docker run --memory=512m nginxThe --memory flag sets the container’s memory limit. If the container reaches that limit and the kernel cannot reclaim enough memory to satisfy a new allocation, an Out of Memory (OOM) event can occur, and the kernel may terminate a process inside the container.
You can also run a container without specifying a memory limit:
docker run nginxWithout a configured limit, the container can use available memory on the host. This can become a problem when multiple containers are running on the same machine, and one container starts consuming a large amount of memory.
Container memory vs. host memory
Container memory is the memory used by a specific Docker container. Host memory is the total memory available to the machine running Docker.
Containers use the host’s memory rather than having a separate pool of physical RAM. Docker Engine uses Linux cgroups to track and control how much memory each container can consume.
For example, a host with 16 GB of RAM might be running three containers:
Container A: 2 GB
Container B: 1 GB
Container C: 512 MBThe containers account for only part of the host’s memory usage. The OS, the Docker daemon, and the filesystem cache also consume memory. If you watch both levels, you’ll see exactly where the memory goes. Container metrics show which workloads are chewing up memory, while host metrics reveal whether the host can support all workloads.
Why is monitoring Docker memory usage important?
By tracking Docker memory usage, you’ll be able to avoid OOM kills, discover memory leaks, troubleshoot performance issues and implement correct memory limits.
1. Prevent Out of Memory (OOM) kills
If the kernel doesn’t have enough memory to reclaim when a container’s memory limit is hit, an OOM event may occur, which could lead to process killing.
As a result, monitoring memory usage can help detect containers whose memory consumption approaches the limit before they are OOM-killed.
2. Detect memory leaks
A memory leak occurs when an application continues to allocate memory without releasing it. Tracking memory over time makes this easier to spot. For example:
250 MiB → 310 MiB → 390 MiB → 470 MiBSteady growth under a stable workload can indicate that an application is retaining memory.
3. Troubleshoot performance problems
Memory pressure can contribute to application slowdowns and instability. Comparing memory usage with CPU usage, request rates, and latency can help determine whether memory is part of the problem.
4. Set appropriate memory limits
Memory usage data helps you set limits based on actual workload behavior. A limit that is too low can cause unnecessary OOM kills, while an excessively high limit can reserve memory that other workloads could use.
Understanding Docker memory metrics and components
Docker memory monitoring includes several metrics that show how much memory a container is using, how close it is to its configured limit, and what drives that usage. Understanding these metrics makes it easier to interpret docker stats output and investigate unusual memory consumption.
| Metric | What it means |
|---|---|
| Memory usage | Current memory consumed by the container. docker stats shows this as MEM USAGE / LIMIT. |
| Memory limit | Maximum memory allocated to the container. |
| RSS | Memory currently resident in physical memory, including application heaps and stacks. |
| Cache | Memory used by the kernel for filesystem caching. It can often be reclaimed when memory is needed. |
| Working set | Memory considered actively in use and less readily reclaimable. Commonly reported by tools such as cAdvisor. |
| Swap usage | Memory moved from RAM to swap. Heavy swap activity can affect application performance. |
For example, 420 MiB / 512 MiB means the container is using about 82% of its configured memory limit. If usage continues to increase, comparing these metrics can help determine whether the increase is coming from application memory, cache, or memory pressure.
How to monitor Docker memory usage with docker stats
Docker stats is Docker’s built-in command for monitoring resource usage in running containers. It provides a live view of memory, CPU, network, and block I/O usage without requiring additional tools.
Running docker stats
Run the following command to monitor all running containers:
docker statsThe output should look similar to this:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
a1b2c3d4e5f6 api 2.15% 340MiB / 512MiB 66.41% 1.2MB / 900kB 15MB / 4MBThe command continues updating the values while it runs. Press Ctrl+C to stop monitoring.
Understanding the docker stats output
The default output includes several resource metrics. For memory monitoring, focus primarily on MEM USAGE / LIMIT and MEM %.
| Column | What it shows |
|---|---|
| CONTAINER ID | Short ID of the container |
| NAME | Container name |
| CPU % | CPU usage |
| MEM USAGE / LIMIT | Current memory usage against the configured limit |
| MEM % | Memory usage as a percentage of the limit |
| NET I/O | Network data sent and received |
| BLOCK I/O | Data read from and written to disk |
| PIDS | Number of processes running in the container |
For example, 340MiB / 512MiB means the container is using 340 MiB out of its 512 MiB memory limit, while 66.41% shows the percentage of that limit currently in use.
The memory values show the container’s current state. To identify gradual increases or unusual patterns, you need to track them over time.
Monitoring a specific container
To watch one container (or a few) instead of the whole host, pass the container name or ID:
docker stats webUsing –no-stream
The live view is useful for watching a trend, but sometimes you just need one reading, for example in a script or a quick check before you deploy. --no-stream Prints a single snapshot and exits instead of continuously refreshing:
docker stats --no-stream
# You can also combine it with a specific container:
docker stats --no-stream apiFormat docker stats output
The default output includes several resource metrics. If you only need memory-related values, use the --format option:
docker stats --format "{{.Name}}t{{.MemUsage}}t{{.MemPerc}}"This produces a smaller output containing the container name, memory usage and limit, and memory percentage.
Docker stats is useful for quick inspection and troubleshooting, but it has limitations. It does not provide historical memory trends, long-term alerting, or correlation with application metrics, logs, and traces. For these use cases, you need a monitoring or observability solution that continuously collects Docker memory metrics.
Setting memory limits for Docker containers
Setting a memory limit prevents a container from consuming more memory than you have allocated to it. This helps keep one container from exhausting memory needed by other workloads on the same host.
Set a memory limit with–– memory
Use the --memory flag when starting a container:
docker run --memory=512m nginxThis limits the container to 512 MiB of memory. You can also use values such as 1g or 2g.
If the container reaches its limit and cannot reclaim memory, an OOM event can occur.
Set memory and swap limits
Use --memory-swap to control the combined amount of memory and swap available to the container:
docker run --memory=512m --memory-swap=1g nginxIn this example, the container can use up to 512 MiB of memory and 1 GiB of combined memory and swap.
To prevent the container from using swap, set both values to the same amount:
docker run --memory=512m --memory-swap=512m nginxSet memory limits with Docker Compose
You can also define a memory limit in Docker Compose:
services:
app:
image: my-app
mem_limit: 512mChoose limits based on actual memory usage rather than setting them arbitrarily. Monitor the container under normal and peak workloads, then leave enough headroom for expected increases.
A limit that is too low can cause unnecessary OOM kills, while a limit that is too high can leave less memory available for other containers.
Common causes of high Docker memory usage
High Docker memory usage does not always indicate a memory leak. The cause can be application behavior, caching, workload changes, or an incorrectly configured container.
Growing application caches
Applications may store frequently accessed data in memory to improve performance. If a cache grows without an effective size limit or eviction policy, it can consume a significant amount of container memory. Check the application’s cache configuration before treating increasing memory usage as a leak.
Increased workload
Higher traffic, larger requests, more concurrent connections, or larger datasets can naturally increase memory consumption. Compare memory usage with traffic and application metrics to determine whether the increase matches a change in workload.
Insufficient memory limits
A container may consistently approach its memory limit simply because the limit is too low for its workload. For example, an application that normally uses 450 MiB with occasional spikes to 500 MiB may repeatedly approach a 512 MiB limit.
Before increasing the limit, check historical memory usage to determine whether the workload has actually grown or whether the application is using more memory than expected.
Troubleshooting Docker memory issues
When a container uses more memory than expected, start by checking its current memory usage and configured limit. Then compare the results with historical memory usage, workload changes, and application behavior to narrow down the cause.
Container keeps restarting
Check the container’s status and logs:
docker ps -a
docker logs <container_name>If the container was terminated because of an OOM event, check its state:
docker inspect <container_name> --format='{{.State.OOMKilled}}'A result of true means the container was OOM-killed.
Container is OOM-killed
Check the container’s current memory usage and limit:
docker stats --no-stream <container_name>If memory usage is consistently near the limit, review historical usage and workload before increasing the limit. A memory leak, increased workload, or growing cache may be responsible.
Host is running out of memory
Check memory usage across running containers:
docker stats --no-streamCheck the host’s available memory with its operating system tools. If several containers are consuming large amounts of memory, review their limits and workloads instead of troubleshooting each container in isolation.
Memory usage keeps increasing
A steady increase under a stable workload can indicate a memory leak. Track the container’s memory usage over time and compare it with traffic, application behavior, RSS, and cache. If memory usage continues to increase without a corresponding change in workload, investigate the application for retained objects, unbounded caches, or other sources of memory growth.
Monitoring Docker memory with cAdvisor, Prometheus, and Grafana
Docker stats is useful for checking the current state of your containers. But it does not store historical metrics or provide built-in alerting. cAdvisor can continuously collect container resource metrics. Prometheus stores those metrics over time.
Grafana provides dashboards for visualizing them. If you’re weighing this stack against other options, our guide to Docker monitoring tools compares open-source and platform options side by side.
What cAdvisor collects
cAdvisor runs on the Docker host and collects resource usage metrics for running containers. These include memory, CPU, network, and filesystem metrics.
For memory monitoring, cAdvisor exposes metrics such as:
- container_memory_usage_bytes for total container memory usage
- container_memory_working_set_bytes for the container’s working set
- container_memory_rss for resident memory
- container_memory_cache for cache usage
You can run cAdvisor as a container:
docker run -d
--name=cadvisor
--privileged
--device=/dev/kmsg
-p 8080:8080
-v /:/rootfs:ro
-v /var/run:/var/run:ro
-v /sys:/sys:ro
-v /var/lib/docker/:/var/lib/docker:ro
-v /dev/disk/:/dev/disk:ro
gcr.io/cadvisor/cadvisor:<VERSION>Replace <VERSION> with the cAdvisor version you want to run. Once cAdvisor is running, you can access its metrics endpoint and inspect the container metrics it exposes.
Collecting cAdvisor metrics with Prometheus
cAdvisor exposes its metrics in a format Prometheus can scrape. Add cAdvisor as a scrape target in your Prometheus configuration:
scrape_configs:
- job_name: 'cadvisor'
static_configs:
- targets: ['cadvisor:8080']Prometheus then periodically collects and stores metrics, allowing you to query container memory usage over time rather than only the current value.
For example, you can query a container’s working set with:
container_memory_working_set_bytes{name="web"}Visualizing memory trends with Grafana
Grafana connects to Prometheus as a data source and turns these queries into dashboards, which is usually more useful day-to-day than reading raw PromQL output. A typical Docker memory dashboard includes a per-container usage-versus-limit graph, a ranked table of containers by memory percentage, and a panel tracking OOM kill counts over time, so a spike is visible at a glance instead of requiring a query first.
How to monitor Docker memory usage with Middleware
If docker stats only gives you a point-in-time view, Middleware lets you monitor container memory usage from a centralized dashboard and track it over time. The Docker Infra Agent collects container metrics and makes them available in Middleware’s Infrastructure view, Dashboard Builder, and alerting tools.
Step 1: Deploy the Middleware Host Agent
Run the quick install script on the host machine running Docker. Replace YOUR_API_KEY and YOUR_TARGET_URL with your Middleware account credentials:
MW_API_KEY="<MW_API_KEY>"
MW_TARGET="https://<MW_UID>.middleware.io:443"
bash -c "$(curl -fsSL https://install.middleware.io/scripts/docker-install.sh)"Note: The agent requires Docker Engine 19.03 or later and cgroup memory management to be enabled to collect container metrics.
After installation, verify that the agent is running:
docker ps -a --filter ancestor=ghcr.io/middleware-labs/mw-host-agent:masterThen open Infrastructure → Installation in Middleware and confirm that the host appears with a recent Last seen timestamp. Metrics can take a few minutes to appear.
Step 2: View Docker memory metrics
Once the agent starts sending data, the Docker container metrics become available in Middleware.
The Docker Agent exposes memory metrics including:
- container.memory.usage.total
- container.memory.usage.limit
- container.memory.rss
- container.memory.percent
- container.memory.fails
- container.memory.cache
Step 3: Create a memory dashboard
Open Dashboard Builder and create a dashboard for the Docker memory metrics you want to monitor. You can add widgets for metrics such as container.memory.usage.total, container.memory.usage.limit, and container.memory.percent.
Middleware’s Dashboard Builder lets you create custom dashboards from the metrics being ingested into the platform. This gives you a persistent view of container memory usage instead of manually checking docker stats.
Step 4: Analyze and investigate memory usage
Use the dashboard to review container memory usage across different time ranges. Look for sustained increases, recurring spikes, or containers that consistently approach their memory limits. Compare memory metrics to understand how consumption changes over time.
When you identify unusual memory behavior, compare memory trends with logs, application errors, and other infrastructure metrics in Middleware to investigate the possible cause of the increase.
Step 5: Create a memory alert
Create a metric alert for the container memory metric you want to monitor.
In Middleware’s alert builder, select Container as the resource, choose the relevant memory metric, define the aggregation and threshold, and configure the notification.
For example, you could create an alert for sustained high container.memory.percent so that you are notified before a container repeatedly hits its memory limit.
FAQs
How do I check Docker memory usage?
Run docker stats for a live view of every running container’s memory usage and limit. Add –no-stream if you just want a single reading instead of a continuously updating stream.
What is the difference between RSS and cache?
RSS is memory actively allocated by a process, including heap and stack data, and it stays in use until the process releases it or is killed. Cache is memory the kernel uses to hold recently accessed filesystem data, and it can be reclaimed automatically whenever the system needs the space elsewhere. A container’s total memory usage can include both, so telling them apart matters when deciding whether growth is a leak or just normal caching.
Why does Docker use more memory than my application?
The memory usage Docker reports for a container includes more than what your application code allocated. It also includes shared libraries, runtime overhead, and filesystem cache the kernel is holding on the container’s behalf. A large gap between what your app allocates and what docker stats shows is usually explained by cache, not a problem with the application itself.
What causes Docker OOMKilled?
A container can be OOM-killed when it reaches its memory limit and the kernel cannot reclaim enough memory to satisfy a new allocation. Rather than let the container keep growing and risk destabilizing the host, the kernel’s OOM killer terminates a process inside the container, which shows up as exit code 137 in docker ps -a.
Does docker stats include cache?
On Linux, docker stats subtracts reclaimable page cache from the total memory charged to the container’s cgroup before displaying MEM USAGE. That makes the number closer to what the application is actually using than the raw cgroup total, though it still isn’t the same as RSS.
How can I monitor Docker memory in production?
docker stats is fine for a quick check on a single host, but production monitoring needs history and alerting. That means pairing cAdvisor with Prometheus and Grafana, or using a platform like Middleware that collects the same data with less setup. Either way, you get to see memory trends over time and get notified before a container hits its limit, instead of finding out after an OOM kill already happened.
What is the best Docker memory monitoring tool?
It depends on scale and how much setup you’re willing to maintain. docker stats is enough for a single host and quick troubleshooting, cAdvisor with Prometheus and Grafana is a solid open source option if you’re willing to run and maintain three services, and a platform like Middleware fits better if you want memory metrics, alerts, logs, and traces already connected without building that pipeline yourself. Our roundup of Docker monitoring tools breaks down the tradeoffs across all three approaches.
Why does docker stats show different memory usage than top or free?
docker stats reports memory for the container’s cgroup as a whole, with reclaimable cache subtracted out. top and free report on individual processes or total system memory using different accounting, and running top inside a container typically shows host-level memory rather than the container’s actual cgroup limit. That mismatch in what each command is measuring is why the numbers rarely line up exactly.

