Skip to content
Commitwise
Menu

Your Spring Boot service in Kubernetes keeps restarting with exit code 137. How do you investigate and fix it?

BackendSenior

In shortExit 137 is a kill by the kernel's OOM killer when the container goes over its memory limit, not a Java OutOfMemoryError. Usually the heap is sized too close to the limit; leave headroom with MaxRAMPercentage around 75% and check non-heap memory with Native Memory Tracking.

Model answer

What 137 means: 128 + 9, the process got SIGKILL. In Kubernetes the pod status shows OOMKilled: total process memory crossed the container’s memory limit and the kernel killed it instantly, so there’s no Java stack trace.

Why it happens: the JVM uses more than its heap. Metaspace (100–200 MB for a Spring app), the code cache, about 1 MB per platform thread stack, direct buffers for Netty and HTTP clients, and GC structures all live outside -Xmx. A config like -Xmx2g in a 2 GiB container is guaranteed to get killed once the heap fills up.

How to investigate:

  1. Confirm OOMKilled in kubectl describe pod and look at the memory graph: a slow climb (leak or growing cache) or a spike (a large request, a burst of threads)?
  2. Check the JVM flags actually in effect (jcmd <pid> VM.flags) and the heap size the JVM picked.
  3. Enable -XX:NativeMemoryTracking=summary and compare jcmd <pid> VM.native_memory summary with the container’s memory usage to see which area grows.
  4. If the heap itself grows, take a heap dump (-XX:+HeapDumpOnOutOfMemoryError, or jcmd GC.heap_dump) and look for the leak.

Fix: size the heap as a percentage, -XX:MaxRAMPercentage=75, so a quarter of the limit is left for everything else; add -XX:+ExitOnOutOfMemoryError for clean restarts; cap thread pools and off-heap caches. Only raise the limit once you know what the memory is for.

What they're looking for

Knowing 137 means SIGKILL from the cgroup OOM killer, that JVM memory is heap plus metaspace, code cache, thread stacks and direct buffers, container-aware defaults (25% heap), percentage-based sizing, and a measured investigation instead of just raising the limit.

Common mistakes

  • Searching the logs for an OutOfMemoryError that never gets written.
  • Setting -Xmx equal to the container limit.
  • Raising the memory limit without finding what grows.
  • Forgetting thread stacks when a pool has hundreds of platform threads.

More backend questions

Esc

Type to search the whole site.