Why Does a Running Container Keep Its Old Memory Limit After the Compose File Changes?

Eva Wong is the Technical Writer and resident tinkerer at ZimaSpace. A lifelong geek with a passion for homelabs and open-source software, she specializes in translating complex technical concepts into accessible, hands-on guides. Eva believes that self-hosting should be fun, not intimidating. Through her tutorials, she empowers the community to demystify hardware setups, from building their first NAS to mastering Docker containers.

A running container keeps its old memory limit when the edited Compose configuration was never applied to that container’s live cgroup.

Changing YAML does not modify an existing container by itself, and an ordinary restart starts the same container with the same creation-time configuration. Confusion also comes from comparing a hard memory limit with a reservation, swap allowance, parent systemd scope, or application heap setting. Diagnose the effective cgroup value and container ID before deciding that Docker ignored the change.

Read the Live Cgroup Limit Instead of Trusting the YAML

Record the container ID, creation time, Docker inspection output, cgroup version, and the memory-control files used by the running process.

The Linux kernel defines memory.max as the cgroup hard limit, while memory.high applies reclaim pressure without acting as the same absolute ceiling.

If the live cgroup still contains the old value, the configuration was not applied. If it contains the new value but monitoring disagrees, check units, cache accounting, swap, and application-level metrics.

Distinguish Restart From Container Recreation

Compare the container ID before and after the command used to deploy the change. Record whether the command was restart, up, create, a NAS UI action, or a direct Docker update.

Docker states that Compose restart does not apply configuration changes, because it restarts the existing service containers.

Use a controlled Compose update that recreates the service, or a supported live resource update when appropriate. Preserve the old inspection output so the changed field can be verified.

Validate the Final Compose Model and Memory Field

Render the effective Compose configuration after all files, profiles, and environment substitutions are applied. Check whether the limit belongs to the active service.

The Compose specification defines mem_limit as a service memory limit and requires consistency when equivalent deploy limits are also declared.

A value in an unused override file, inactive profile, misspelled service, or different Stack UI does not change the deployed model. Compare the rendered configuration with Docker inspection.

Separate Hard Limit, Reservation, and Swap

Record the hard memory limit, reservation or soft limit, swap limit, current usage, peak usage, and OOM events. Do not treat every memory-related value as one ceiling.

Systemd’s resource-control documentation distinguishes MemoryHigh from MemoryMax and shows that parent cgroups can impose additional limits on services and containers.

A container can appear to exceed a reservation because a reservation is not the same as a hard cap. It can also consume swap or page cache that one dashboard excludes or reports separately.

Check Whether the Runtime Heap Uses Its Own Ceiling

For Java applications, record container-aware JVM detection, maximum heap, direct memory, metaspace, thread stacks, and the flags passed by the image or app configuration.

Oracle documents that the JVM sizes its heap from available memory constraints and allows MaxRAMPercentage to set the heap fraction.

Changing the container limit may not produce the expected application heap when an explicit -Xmx or percentage remains in place. Heap memory is also not the process’s total memory use.

Check Node.js and Other Application-Level Limits

Inspect runtime flags, environment variables, worker counts, caches, and internal memory targets. Compare them with the operating-system limit.

Node.js documents max-old-space-size as a V8 heap limit, which can remain unchanged even after the container receives a larger or smaller cgroup allowance.

A container limit protects the host; it does not automatically tune every application. Set the runtime below the container ceiling with room for native allocations and filesystem cache.

Apply One Change and Verify Under a Controlled Load

Render the final Compose model, recreate only the affected service, confirm the new container ID and live cgroup, then run a bounded workload while watching usage and OOM events.

The ZimaSpace Tech & AI Hub article explains what happens at an active container limit; this article focuses on proving that a changed limit was actually deployed.

The issue is resolved when the rendered configuration, container inspection, cgroup files, runtime heap, and observed failure boundary all match the intended policy after reboot.

Frequently Asked Questions

Does restarting a container apply a changed Compose memory limit?

No. A restart normally uses the same existing container configuration. Recreate the service or use a supported live update.

Can a container temporarily exceed its hard memory limit?

Kernel accounting and reclaim can briefly show values near or slightly beyond a boundary, but sustained unreclaimable use at the hard limit leads to cgroup OOM handling.

Why does the app still report the old heap size?

The application runtime may have an explicit heap flag or may calculate a percentage only at startup. Recreate or restart it after validating the container limit.

Support & Tips

More to Read

Get More Builds Like This

Stay in the Loop

Get updates from Zima - new products, exclusive deals, and real builds from the community.

Stay in the Loop preferences

We respect your inbox. Unsubscribe anytime.