“The pod keeps getting OOMKilled but the heap is only 512 MB.” “Latency doubles every few seconds and the CPU graph looks fine.” Both of these come from the same root cause: Kubernetes resource settings that don't match how the JVM actually uses memory and CPU.
Memory: the heap is not the whole process
A Java process uses heap plus metaspace, thread stacks, the code cache, GC structures and direct buffers. If you set -Xmx512m and a 512Mi container limit, the kernel will kill the container long before Java ever throws an OutOfMemoryError.
Let the JVM size itself from the container limit instead:
env:
- name: JAVA_TOOL_OPTIONS
value: "-XX:MaxRAMPercentage=75 -XX:+ExitOnOutOfMemoryError"
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "1Gi"
- 75% leaves room for non-heap memory. For apps with many threads or heavy off-heap use (Netty, large caches) go to 60–65%.
- Memory request = memory limit. Memory is not compressible; a pod that bursts above its request is the first to be evicted when the node is under pressure.
ExitOnOutOfMemoryErrormakes a heap OOM a clean restart instead of a half-dead JVM.
CPU: limits cause throttling
CPU limits are enforced in 100 ms windows. A JVM with several GC and JIT threads can use its whole quota in the first 20 ms and then sit throttled for 80 ms. That shows up as random latency spikes even though average CPU looks low.
- Set a realistic CPU request so the scheduler places pods sensibly.
- Either don't set a CPU limit, or set it well above the request (2–4×) for latency-sensitive services.
- Watch
container_cpu_cfs_throttled_periods_totalin Prometheus; if it climbs, the limit is too tight. - The JVM sizes thread pools from the CPU count it sees. If needed, pin it with
-XX:ActiveProcessorCount=2.
Finding the right numbers
- Run under realistic load and watch
kubectl top podplus JVM metrics from Actuator/Micrometer. - Install the Vertical Pod Autoscaler in recommendation-only mode and read its suggestions for a week.
- Set requests around normal peak usage, then revisit after big releases.
Quick diagnosis
- Reason: OOMKilled, exit code 137 – container limit hit; lower
MaxRAMPercentageor raise the limit. java.lang.OutOfMemoryErrorin logs – heap is too small for the workload, or there is a leak.- Latency spikes, CPU looks low – check throttling before you blame the code.
No comments:
Post a Comment