That CUDA out of memory error isn’t just frustrating—it’s a lie of omission. It tells you the GPU is full, but not why your 7.93 GiB card choked on a 20 MiB allocation. PyTorch has shipped a built-in memory profiler that finally makes the difference between allocated and reserved memory visible, and using it reveals a counterintuitive truth about how deep learning frameworks horde VRAM.

The tool works by recording a snapshot of every allocation and free event. You wrap your code with torch.cuda.memory._record_memory_history(), run a few iterations, and dump a pickle file. Dragging that into the visualizer at pytorch.org/memory_viz shows a timeline that reads like an EKG for your GPU. A simple nn.Linear(10_000, 50_000) model immediately grabs 2 GB just for its parameters—that’s the blue block that never budges. Then things get interesting.

In a loop, creating a 200 MB input tensor spikes memory, but the forward pass adds another 1 GB for the output and activations. The real shocker is what doesn’t happen: that first input tensor isn’t freed after the second iteration starts. The model hangs onto it because the activation is still referenced for a backward pass that may never come. This is the silent killer in inference scripts. PyTorch’s caching allocator also plays a role—the 6.00 GiB reserved in total message in the error means the framework is holding onto memory it’s already freed, waiting to reuse it, but the OS sees it as gone.

Scaling up to a real model like Qwen2.5-1.5B with an AdamW optimizer, the profile shows three distinct spikes per training step. The forward pass balloons memory with activations, loss.backward() pushes it even higher as it computes gradients, and optimizer.step() adds optimizer state tensors before zero_grad() finally lets it all collapse. If you’re running validation or inference and still seeing OOMs, wrapping the forward call in torch.no_grad() is the single most impactful line you can add—it tells PyTorch to stop hoarding those activations immediately. The profiler file itself will bloat to 8 MB for just three training steps, so keep your captured iterations brutally short.