advanced27 min studyLesson 468 in Engineering

Device allocator fragmentation

Read live and reserved accounting correctly, preserve stream-ordered lifetimes, and distinguish suballocator fragmentation from physical-contiguity myths.

On this page

What you’ll understand

  • Separate application-live, safely reusable, and reserved memory.
  • Explain allocation and release dependencies across streams.
  • Analyze a stated suballocator model without assuming physical contiguity.

A training process can reserve far more device memory than its currently live tensors occupy. That observation can reflect deliberate caching, pending asynchronous work, or fragmentation rather than an actual leak. This lesson follows CUDA 12.8.1 stream-ordered allocator and memory-pool documentation on a supported Ampere-class platform. Framework suballocators add their own policies, so measurements need precise definitions of allocated, used, reserved, cached, and reusable memory.

Account for lifetimes before diagnosing a leak

A pool can retain backing memory after an application allocation becomes safely reusable. CUDA exposes reserved-memory and used-memory attributes with documented meanings; a framework’s similarly named counters need not have identical accounting boundaries. Compare counters over repeated equivalent workload phases and after appropriate completion points. A stable high-water reserve differs from unbounded growth of genuinely live allocations. Record which stream owns the final use and whether outstanding operations still need the allocation when collecting a diagnostic snapshot.

For a declared simplified pool, partition the reserved bytes into mutually exclusive live allocations, safely reusable free space, and other accounted overhead. A pending release remains unavailable until its ordering conditions permit reuse; do not subtract it just because a host call returned. Real allocators may distinguish allocation granularity, metadata, inaccessible regions, or external backing. An accounting equation is useful only if its terms cover the same pool at the same observation boundary, without counting one region twice.

R=L+F+OR=L+F+O
In an explicitly partitioned toy pool, reserved bytes R equal live or not-yet-reusable bytes L, safely reusable bytes F, and other bytes O. This is not an assertion that every framework exposes these exact counters or that CUDA reserved-minus-used is a universal fragmentation metric.↔ Scroll wide equations horizontally.

Stream ordering determines eligibility for reuse

cudaMallocAsync and cudaFreeAsync place allocation and release into stream order. An allocation must become available before its first use, and its release must follow every relevant use. When another stream accesses it, establish the necessary dependency through supported synchronization rather than assuming that host submission order across streams is sufficient. Memory-pool reuse policies can use dependencies or introduce documented dependencies to enable reuse, but those policies do not excuse an application that frees memory before a still-unordered consumer finishes.

Caching released backing can avoid expensive allocation activity at the cost of retaining a larger reserve. Trimming a pool can release eligible unused backing under its documented behavior; it cannot make an actively used tensor disappear safely. Aggressive trimming or synchronization can also hurt throughput, so memory reduction and latency form a workload-specific tradeoff. For variable-length inference batches, bound shape diversity or reuse suitable buffers when that preserves semantics, then measure both peak eligible storage and request latency.

fexternal=1−FlargestFtotal,Ftotal>0f_{\mathrm{external}}=1-\frac{F_{\mathrm{largest}}}{F_{\mathrm{total}}},\qquad F_{\mathrm{total}}>0
This dimensionless diagnostic belongs to a declared free-block suballocator model: largest eligible free block divided by total eligible free bytes. It is not a universal CUDA memory-pool attribute, and it does not include every source of unusable capacity.↔ Scroll wide equations horizontally.

State which allocator cannot satisfy the request

Enough total free bytes need not imply one suitable block in a particular suballocator. For example, a fixed arena requiring a contiguous virtual subrange can fail when free regions are separated by live allocations. That example does not imply that CUDA generally requires physically contiguous device DRAM. Virtual-memory mapping, coalescing policies, size classes, alignment, and driver allocation can change the outcome. Describe the constrained allocator instead of diagnosing every out-of-memory error with the same fragmentation story.

The queue lab gives only an analogy for pending releases. Reset, set arrival rate to 0 and service rate to 4, predict the backlog at one second, then Step twice; its initial four units drain to zero. Compare a fresh Reset with both arrival at 2 and service at 4 before two Steps; two units remain. Changing a control preserves elapsed time, so the explicit Reset matters. The instrument contains no pointers, free lists, byte sizes, or CUDA streams.

Free bytes versus one eligible block

Assume a fixed 100-MiB suballocator arena with 60 MiB live, no overhead, and three separated eligible free blocks of 10, 15, and 15 MiB. This toy cannot remap or grow the arena. Can it provide one 20-MiB virtual block?

  1. The free total is 10 + 15 + 15 = 40 MiB, and reserved equals 60 + 40 = 100 MiB. There are enough free bytes in aggregate.

  2. The largest block is only 15 MiB, so this allocator cannot satisfy a 20-MiB request. Its stated external-fragmentation diagnostic is 1 − 15/40 = 0.625, or 62.5%.

  3. If a later release makes the 10-MiB and one 15-MiB region adjacent and coalescing is permitted, the combined region contains at least 25 MiB, plus any released separator bytes, and can satisfy the request. This does not require a claim about physical DRAM contiguity.

The result

A specific placement constraint explains the toy failure; total reserve alone proves neither fragmentation nor a leak.

Explore the model

Interactive lab

Interactive lab · queue

Pending releases as an accounting analogy

Reset, set λ = 0 and μ = 4, predict Q at one second, then Step twice: Q = 0. Compare a fresh Reset with both λ = 2 and μ = 4 before two Steps: Q = 2. This fluid backlog begins at four; it does not model byte allocation, fragmentation, CUDA streams, or pool reuse.

Pending releases as an accounting analogyFluid 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 forOutstanding work can delay eligibility for reuse, while actual allocator accounting needs byte and lifetime evidence.

Check your understanding

A process reserves 12 GiB while its reported live tensor storage is 8 GiB. Which conclusion is justified from those two numbers alone?

Try it yourself

A fixed 128-MiB toy arena has 80 MiB live and 48 MiB safely free, with a largest eligible block of 24 MiB. It cannot grow, remap, or coalesce those regions. Evaluate a 32-MiB request and the stated external-fragmentation diagnostic.

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

Give me a hint

Check the largest block separately from the free total. Do not include pending releases in safely free space.

Compare with the solution

Although 48 MiB exceeds the request, the largest available block is 24 MiB, so the request fails in this constrained allocator. The diagnostic is 1 − 24/48 = 0.5. A different allocator with remapping or growth may behave differently; this is not a general proof that the GPU lacks enough physical memory or that cached blocks may be released while users are in flight.

Take it with you

  • Reserved backing and application-live storage need distinct accounting boundaries.
  • Stream-ordered release is safe only after all required users are ordered before it.
  • Fragmentation claims must name the allocator constraints rather than assume physical contiguity.

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.