advanced29 min studyLesson 710 in Engineering

Attribute memory growth at the tensor, allocator, pool, and device boundaries

Distinguish retained tensors, cached reservation, logical pool leaks, external allocations, and transient peaks with synchronized workload evidence and versioned diagnostic tools.

On this page

What you’ll understand

  • Interpret allocated, reserved, and device-level counters without double-counting.
  • Design a bounded repeated-workload experiment that separates warmup from persistent growth.
  • Classify OOM evidence across live references, cached blocks, fragmentation, and external allocations.

An OOM message reports that a resource request failed; it does not identify why memory was unavailable. A steadily growing tensor footprint, a warmed allocator cache, a leaked KV reference, an oversized temporary workspace, and another process's allocation can produce different symptoms that look similar on a single dashboard. Reconstruct the timeline at matching boundaries. A useful investigation ties allocations and pool ownership to requests and completion events rather than treating high device usage or a large reserved-minus-allocated gap as a sufficient diagnosis.

Counters have different ownership scopes

PyTorch 2.9 documents memory_allocated as tensor-occupied memory and memory_reserved as capacity managed by its caching allocator. A backing KV-pool tensor can remain allocated even when application blocks become free. Conversely, a logical reference leak can exhaust that fixed pool without changing either tensor counter. Device-level tools can include runtime contexts, allocations outside the framework, and other processes, so their totals need not equal the framework's reservation. Compare counters on the same device and time window, with the allocator backend and process scope recorded.

The same documentation explains that empty_cache releases unused allocator cache rather than live tensor storage. It cannot free objects still held through output lists, closures, callbacks, views, or other references. A snapshot's apparent free blocks may also be constrained by pending stream events or allocation size. Do not add allocated and reserved bytes as independent categories, since the former normally sits inside the latter under the standard native caching allocator. Capture their difference as allocator-held capacity not currently reported as tensor allocation, then inspect its state instead of naming all of it a leak.

R=A+H,0≤A≤RR=A+H,\qquad 0\le A\le R
For the stated standard native caching-allocator boundary, A is tensor-allocated bytes, R reserved bytes, and H=R−A allocator-held bytes outside that allocated count. H can include cached or pending states and is not guaranteed immediately reusable for every request. Custom allocators and external CUDA allocations need separately defined counters.↔ Scroll wide equations horizontally.

Reproduce growth after warmup and after safe cleanup

Run a controlled repeated workload with fixed model, shapes, request limits, prefix policy, and bounded output retention. Warm up expected kernels and graph pools, then drain requests and synchronize at declared diagnostic checkpoints before comparing residual live usage. Synchronization can change overlap and performance, so use it deliberately for attribution rather than leaving it in every production path. Compare tensor counters with active block references, idle cached blocks, outstanding transfer buffers, and request registries. An increasing count of completed requests still owning blocks is different evidence from a stable cache reaching its intended capacity.

Use the versioned PyTorch memory-history and snapshot facilities to trace framework-managed allocations and their call stacks. Their documented visibility excludes allocations made directly through other CUDA APIs; NCCL is one common example. A device-level residual suggests further investigation, not automatic attribution to that particular library. Record driver and runtime versions, backend configuration, concurrent processes, and exact failing allocation size. Keep diagnostic metadata useful without dumping raw user prompts or sensitive cached contents into an uncontrolled report. A trace should support an ownership explanation and a reproducible fix.

ℓ^=An2−An1n2−n1,n2>n1\widehat\ell=\frac{A_{n_2}-A_{n_1}}{n_2-n_1},\qquad n_2>n_1
A_n is residual allocated bytes after equivalent warm, drained, safely completed workload checkpoints, and n counts completed comparable requests. The slope has units bytes/request. Persistent positive slope is evidence of retained growth under these controls, not a proof of one cause; bounded caches, changing shapes, and delayed completion can confound it.↔ Scroll wide equations horizontally.

Classify the failed resource before choosing a remedy

A live-tensor leak calls for finding and releasing unintended owners; allocator fragmentation calls for evidence about sizes and inactive splits; a fixed KV-pool leak calls for repairing block-reference transitions; an external allocation needs visibility outside the framework; and a transient prefill peak may require a different concurrency limit. Backend-specific allocator options should follow measured evidence, not be applied as a universal OOM cure. Reproduce cancellation, rollback, prefix reuse, and offload completion paths, because resource leaks often occur on exceptional exits rather than the successful short-request path.

The queue lab contrasts a draining workload with a stable nonzero backlog, not allocator memory. Reset, explicitly set BOTH λ=2 and μ=3, predict initial q=4 drains by t=4, then Play or Step eight times. Reset and re-set BOTH λ=3 and μ=3; predict q=4 at t=4. Edits retain t and recompute the original constant-rate trajectory. This fluid model has no tensors, caching allocator, device counters, or leaks. A nonzero steady quantity can reflect ongoing work; the interpretation requires the correct workload boundary and ownership evidence.

Do not add allocated and reserved memory twice

At a synchronized checkpoint under a standard native caching allocator, tensor allocation is six GiB and allocator reservation is eight GiB. A device-level tool reports ten GiB used. Assume the scopes are aligned for this illustrative subtraction and other-process usage has been excluded.

  1. Allocator-held bytes outside the tensor-allocated count are H=8−6=2 GiB. The framework's reservation is eight GiB total, not 6+8=14 GiB.

  2. The device-minus-framework residual is 10−8=2 GiB under the stated scope assumptions. Investigate runtime or external allocations; the subtraction alone cannot name a responsible library or prove a leak.

  3. If comparable post-warmup drained checkpoints show allocated memory growing from six to 6.5 GiB over one hundred completed requests, the residual growth slope is 0.5/100=0.005 GiB per request, or 5.12 MiB per request. Trace the retained owners before assigning a cause.

The result

Matching counter boundaries and controlled growth measurements narrow the diagnosis without mistaking cached reservation or an unexplained residual for a proven leak.

Explore the model

Interactive lab

Interactive lab · queue

A stable nonzero quantity needs a workload interpretation

For EACH run Reset, set BOTH λ and μ, predict, then Play or Step eight times to t=4. From initial q=4, (2,3) drains to zero and (3,3) remains four. Edits retain t/recompute the original constant-rate trajectory. This fluid backlog has no allocator, tensors, driver usage, pool references, or leak detector.

A stable nonzero quantity needs a workload interpretationFluid backlog starts at 4 and follows max(0, 4 + (λ − μ)t). The separate M/M/1 residence-time formula assumes Poisson arrivals, exponential service and λ < μ. Current readings: Fluid backlog: 4; Net rate · λ − μ: −1 /s; M/M/1 mean residence: 1 s. All parameters are adjustable with the labeled controls below.02.557.51001.534.56Elapsed time · sFluid backlogλ < μ
Fluid backlogCurrent time
Fluid backlog
4
Net rate · λ − μ
−1 /s
M/M/1 mean residence
1 s
t = 0 s

Fluid backlog starts at 4 and follows max(0, 4 + (λ − μ)t). The separate M/M/1 residence-time formula assumes Poisson arrivals, exponential service and λ < μ. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.

Look forInterpret memory only after defining workload completion, cache policy, and the ownership scope of each counter.

Check your understanding

After warmup, device usage is high while tensor allocation and KV-pool occupancy remain stable. What is the best next diagnostic step?

Try it yourself

A fixed KV pool's backing tensor stays at four GiB, but after every canceled request one extra application block remains referenced forever. Can stable memory_allocated rule out a leak? Which evidence would locate the resource loss?

Take a moment to make a prediction or work it out on paper. Open a hint when you need one.

Give me a hint

Distinguish the pool allocation from its logical ownership ledger.

Compare with the solution

No. The backing allocation can stay constant while leaked references gradually exhaust its usable blocks. Track active request owners, per-block reference transitions, cancellation completion, and free/idle pool counts across repeated drained runs. The failure is visible in pool capacity and ownership even if framework allocated bytes are flat.

Take it with you

  • Allocated, reserved, pool-occupied, and device-used memory have different scopes.
  • Controlled warm, drained checkpoints distinguish persistent growth from expected caching and pending work.
  • OOM remedies should follow evidence about the failed resource and its actual owners.

Read further

Original sources and deeper explanations to follow at your own pace.

Optional progress, saved in this browser when available. Revisit any lesson at any time.

Lesson not marked complete.