Without limits, a single container can consume all of a host's CPU or memory, starving every other container (and the host itself) sharing that machine — cgroups (mentioned earlier) are what actually enforce whatever limits you set:
docker run --memory=512m --cpus=1.5 myapp
services:
web:
image: myapp
deploy:
resources:
limits:
memory: 512M
cpus: "1.5"
A container that exceeds its memory limit is killed by the kernel's OOM killer (exit code 137, as mentioned above) rather than being throttled — memory limits are hard caps, not soft suggestions. CPU limits behave differently: a container over its CPU limit isn't killed, it's throttled — it simply gets scheduled less CPU time, which shows up as increased latency rather than a crash. This asymmetry matters when diagnosing production incidents: a memory-related crash is sudden and visible in exit codes, while a CPU throttling problem often just looks like unexplained slowness.