A vLLM style serving pod shows healthy GPU memory at startup. Over six to twelve hours, KV-cache utilization climbs monotonically, the scheduler admits fewer concurrent requests, latency rises, and eventually the pod OOMs. Request volume is steady throughout. Diagnose the pattern: what is leaking, what is the upstream trigger, and what three mitigations would you put in place?
Orphaned sequences from abandoned client streams pin KV cache pages forever. Fix with idle reaper, max session age, and end to end cancel propagation from gateway to inference server.
Imagine a coat-check at a busy restaurant. Each guest takes a numbered hanger when they arrive and returns it on the way out. If guests slip out a back door without claiming their coat, the hangers fill up. After enough nights, the rack has no free hangers and new guests get turned away even though the dining room is empty. The KV cache works the same way. Each chat request rents some pages of GPU memory to store its conversation state. The pages come back when the request ends cleanly. But if the user closes the browser tab, the inference engine never gets the end signal, the pages stay rented forever, and the rack slowly fills up. After hours of small leaks, there is no free space left and the pod crashes.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
This is a classic production failure pattern in LLM serving: memory drifts up over hours at steady traffic, then the pod OOMs in the middle of the night. The symptom is recognizable, the cause is consistent, and the fix is a three-layer defense rather than a single patch.
The diagnosis hinges on understanding that the KV cache is owned by individual sequences and released only on explicit events. When those events do not fire, pages pile up. The trigger is almost always client-side disconnects that do not propagate down to the inference engine.
This walkthrough covers the leak mechanism end to end: what the KV cache pool looks like in a paged-attention serving stack, why orphaned sequences accumulate, how the symptom manifests in metrics, the three-layer mitigation strategy, and the adversarial variants that one of the layers exists specifically to catch.
By the end you should be able to recognize the pattern within minutes of looking at the free page count metric, locate the bug in the gateway to inference plumbing layer, and prescribe defenses that hold up under network failures, runaway agents, and malicious clients alike.
How paged KV cache allocation actually works
Modern inference engines (vLLM, TensorRT-LLM, SGLang) manage KV cache as a paged pool. The HBM left over after model weights and activations is carved into fixed-size pages, each holding the K and V vectors for a small block of tokens (typically 16 tokens per page).
When a request arrives, the scheduler reserves enough pages for the prefill plus a buffer for early decode. As decode proceeds, more pages are claimed from the free pool. When the request completes, its pages return to the pool.
Two things complete a request: the model emits an EOS token (or the configured max output tokens cap is hit), or the client explicitly cancels via API. Both result in the scheduler calling the per-sequence cleanup path that returns pages to the free list.
If neither event fires, the sequence sits in the active set indefinitely. The scheduler keeps trying to generate the next token for it, the model keeps producing logits, and the pages keep being held.
Situations where this technique stops working.
2–4 min · Everything important, quickly.
Real products, models, and research that use this idea.
- Anthropic's Claude Opus 4.7 serving fleet wires Envoy SSE disconnect events directly to the inference cancel API to prevent this exact failure.
- vLLM 0.6+ ships a built-in finished-flag watchdog that catches sequences with no progress for a configurable interval.
What an interviewer would ask next. Try answering before peeking at the approach.
QWhy is cancel propagation surprisingly hard to get right across a modern service mesh?
TCP RST does not survive multiple proxy hops cleanly. Each layer (CDN, ingress, service mesh sidecar, gateway) terminates the connection and re-proxies, so the disconnect event is local to each hop. Application-layer cancel must be carried as an explicit signal, often through a shared request-id channel or out of band cancel API. Plus version-skew between gateway and inference can drop the cancel.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Blaming the model or scheduler. The leak almost always lives in the gateway to inference cancel path, where client disconnects are silently dropped.
60 second bullets to scan on the way to the call.
Name the leaking entity and what event normally releases it
Describe how a client disconnect can fail to propagate to the inference server
Same topic, related formats. Practice these next.