On this page
  1. What does OOMKilled actually mean?
  2. How do I find out what’s eating memory?
  3. How do I fix it?
  4. Where AI coding assistants get this wrong
  5. Checklist
  6. FAQ
    1. Is OOMKilled the same as a crash?
    2. Should I just raise the memory limit?
  7. Related topics
  8. Sources
concept

Why Do My Containers Keep Getting Killed (OOMKilled)?

OOMKilled means your container hit its memory limit and the kernel killed it. Learn why it happens, how to find the leak, and how to set limits safely.

Quick answer

  • OOMKilled means the container exceeded its memory limit and the kernel terminated it to protect the host.
  • The usual cause is a memory leak or a workload that needs more memory than the limit allows.
  • Fix it by finding what’s consuming memory, then either raise the limit, cap the workload, or fix the leak.

What does OOMKilled actually mean?

Every container has a memory limit — set by you, the platform, or a default. When the container’s memory usage hits that limit, the kernel’s out-of-memory killer terminates it. You see ‘Killed’ or ‘OOMKilled’ in the container status, and the container restarts (or stays dead, depending on your policy). It’s the kernel enforcing a boundary: an unbounded process would otherwise take down every other process on the host.

How do I find out what’s eating memory?

Check the container’s memory usage over time with docker stats — a steady climb that resets on each restart points to a leak; a flat line near the limit means the workload simply needs more memory. Inside the container, use the language’s profiling tools to find the leak (psutil or tracemalloc in Python, –inspect for Node). Also check whether the app caches aggressively: unbounded caches are the most common AI-generated leak, since nothing ever evicts old entries.

# See live memory usage per container
docker stats --no-stream
# NAME        CPU %     MEM USAGE / LIMIT
# web         12.5%     512MiB / 512MiB   <- pegged at the limit = the OOM source

How do I fix it?

Three levers, in order. First, cap the workload: set a max cache size, a connection pool limit, or a worker count so memory can’t grow unbounded. Second, fix the leak if there is one. Third, set a realistic limit — don’t give a container 512 MB and then wonder why it dies doing work that needs 1 GB. A limit that’s too tight causes constant restarts; no limit at all lets one container starve the host. Also leave headroom: the kernel needs memory for page cache and overhead, so set limits below the host’s total.

Where this bites vibecoders

The first deploy goes fine; a week later the container is in a restart loop and the logs are empty. AI-generated apps leak memory quietly — unbounded caches, unclosed connections, lazy-loaded data that never gets released — and the assistant never set a limit or a test that would reveal it. The tell is OOMKilled in the status. Capping caches and connection pools at generation time prevents the whole class of incident.

Where AI coding assistants get this wrong

  • No memory limit at all, so a leaking container slowly eats the whole host.
  • A limit so tight that normal workload peaks trigger constant restarts.
  • Unbounded in-memory caches and connection pools that grow until OOM.
  • Ignoring the restart loop and blaming ‘flaky infrastructure’ instead of profiling memory.

Checklist

  • Set a memory limit on every container — a bit above measured steady-state usage.
  • Cap caches, connection pools, and worker counts in the app.
  • Watch memory over time (docker stats, platform graphs) for the leak signature.
  • Load-test before deploy so peak memory is known, not discovered in production.

FAQ

Is OOMKilled the same as a crash?

No. A crash is the app exiting on its own — an exception, a panic, a fatal error. OOMKilled is the kernel killing the process from outside because it exceeded its memory limit. The fix paths differ: crashes need code fixes, OOMKilled needs memory management — limits, caps, and leaks.

Should I just raise the memory limit?

Only after confirming the workload legitimately needs more memory. If memory grows without bound, raising the limit just delays the restart. Check the memory graph first: a flat line near the limit means raise it; a steady climb means find the leak.

Sources

Share: