
Lost your password? Please enter your email address. You will receive a link and will create a new password via email.
Please briefly explain why you feel this question should be reported.
Please briefly explain why you feel this answer should be reported.
Please briefly explain why you feel this user should be reported.
PyTorch RuntimeError: CUDA out of memory: Why torch.cuda.empty_cache() fails & how to fix fragmentation
Direct Technical Solution: torch.cuda.empty_cache() releases only cached (unallocated) blocks back to the CUDA driver; it never frees memory occupied by active tensors (weights, optimizer states, computation graph nodes). Calling it inside your training loop hurts performance because CUDA must constRead more
Direct Technical Solution:
torch.cuda.empty_cache()releases only cached (unallocated) blocks back to the CUDA driver; it never frees memory occupied by active tensors (weights, optimizer states, computation graph nodes). Calling it inside your training loop hurts performance because CUDA must constantly re-allocate OS memory via costly system calls.1. Root Cause: PyTorch Allocator Memory Fragmentation
Look closely at your error message:
18.21 GiB allocated+4.80 GiB reserved. PyTorch had nearly 5 GB of memory held in its internal caching allocator, but it was split into scattered, non-contiguous memory chunks. When a tensor required 512 MiB of contiguous VRAM, the allocator failed to find a single chunk large enough.2. The Modern Fix: Expandable Segments (PyTorch 2.0+)
The definitive solution in modern PyTorch is activating virtual memory management via the
expandable_segmentsflag. This instructs CUDA to map physical memory pages to a contiguous virtual memory space, virtually eliminating memory fragmentation:3. The 4 Golden Rules to Prevent CUDA OOM
- Detach Loss Values: Never accumulate raw tensor losses:
- Use Automatic Mixed Precision (AMP): Halve activation memory using native BF16/FP16:
- Gradient Accumulation: Instead of a batch size of 64 that OOMs, use a micro-batch size of 16 and accumulate gradients across 4 backward steps:
- Zero Gradients with `set_to_none=True`:
See lesstotal_loss += lossretains the entire backward computation graph in VRAM! Always usetotal_loss += loss.item().optimizer.zero_grad(set_to_none=True)deallocates memory instead of zeroing tensors with zeros of equal size.Task Scheduler with Cooldowns: Closed-form mathematical formula vs Priority Queue simulation
Here is the C++20 Closed-Form Math implementation for Task Scheduler. It eliminates all simulation loops and runs in O(N) time and O(1) space. Modern C++20 Solution (Fully Runnable) Copy C++ Code ► Compile & Run in Online C++ Runner #include <iostream> #include <vector> #includRead more
Here is the C++20 Closed-Form Math implementation for Task Scheduler. It eliminates all simulation loops and runs in
O(N)time andO(1)space.Complexity:
See lessO(N)time to tally frequencies andO(1)space using a fixed 26-element array.Lowest Common Ancestor: Why Binary Lifting in O(log N) beats naive DFS in high-scale DAGs
Here is the full C++20 Binary Lifting LCA implementation. Any LCA query runs in O(log N) time. Modern C++20 Solution (Fully Runnable) Copy C++ Code ► Compile & Run in Online C++ Runner #include <iostream> #include <vector> #include <cmath> #include <algorithm> classRead more
Here is the full C++20 Binary Lifting LCA implementation. Any LCA query runs in
O(log N)time.Complexity:
See lessO(N log N)preprocessing andO(log N)per query.Minimum Window Substring: Why an integer frequency array beats HashMap in low-latency parsers
Here is the C++20 Minimum Window Substring using a stack-allocated 128-element integer array and std::string_view to avoid memory allocations. Modern C++20 Solution (Fully Runnable) Copy C++ Code ► Compile & Run in Online C++ Runner #include <iostream> #include <string> #includRead more
Here is the C++20 Minimum Window Substring using a stack-allocated 128-element integer array and
std::string_viewto avoid memory allocations.Zero Allocations:
See lessstd::string_viewcreates no heap strings; the array fits into CPU L1 cache.How does a Fenwick Tree (Binary Indexed Tree) query and update prefix sums in O(log N) using i & (-i)?
Here is the clean C++20 Fenwick Tree (BIT) implementation. It uses int64_t for precision and i & (-i) for logarithmic index jumps. Modern C++20 Solution (Fully Runnable) Copy C++ Code ► Compile & Run in Online C++ Runner #include <iostream> #include <vector> #include <csRead more
Here is the clean C++20 Fenwick Tree (BIT) implementation. It uses
int64_tfor precision andi & (-i)for logarithmic index jumps.Complexity:
See lessO(log N)updates and queries with strictly1Nmemory footprint.How does the Dutch National Flag 3-way partition work in a single pass with zero branch mispredictions?
Here is the in-place C++20 Dutch National Flag algorithm. Notice that std::swap compiles to a single XCHG or register mov instruction on x86_64. Modern C++20 Solution (Fully Runnable) Copy C++ Code ► Compile & Run in Online C++ Runner #include <iostream> #include <vector> #inclRead more
Here is the in-place C++20 Dutch National Flag algorithm. Notice that
std::swapcompiles to a singleXCHGor register mov instruction on x86_64.Complexity: Single pass
See lessO(N)withO(1)space.How does a Count-Min Sketch estimate heavy-hitter item frequencies under bounded RAM?
Here is a modern C++ implementation of the Count-Min Sketch for streaming frequency tracking under strict memory caps. Modern C++20 Solution (Fully Runnable) Copy C++ Code ► Compile & Run in Online C++ Runner #include <iostream> #include <vector> #include <string> #includRead more
Here is a modern C++ implementation of the Count-Min Sketch for streaming frequency tracking under strict memory caps.
Guarantees: Strictly bounded RAM overhead and zero underestimations.
See lessGas Station Circular Tour: Mathematical proof of why a single pass in O(N) is sufficient
Here is the clean C++20 Single-Pass Greedy solution for the Gas Station problem. Modern C++20 Solution (Fully Runnable) Copy C++ Code ► Compile & Run in Online C++ Runner #include <iostream> #include <vector> int canCompleteCircuit(const std::vector<int>& gas, const sRead more
Here is the clean C++20 Single-Pass Greedy solution for the Gas Station problem.
Complexity: Strictly
See lessO(N)time andO(1)auxiliary space.How does Brian Kernighan’s bit algorithm work, and why does n & (n – 1) clear the lowest set bit?
Here is the modern C++20 bit-manipulation implementation. In modern C++ (C++20), you also have std::popcount from the <bit> header which compiles to the hardware POPCNT instruction. Modern C++20 Solution (Fully Runnable) Copy C++ Code ► Compile & Run in Online C++ Runner #includeRead more
Here is the modern C++20 bit-manipulation implementation. In modern C++ (C++20), you also have
std::popcountfrom the<bit>header which compiles to the hardwarePOPCNTinstruction.Efficiency: Runs only as many iterations as there are
See less1bits in the integer.0/1 Knapsack: Why does reverse iteration turn O(N*W) space into O(W) space?
Here is the modern C++20 implementation of the 0/1 Knapsack with 1D Backward Sweep. By reserving contiguous memory and sweeping from capacity down to weight[i], we eliminate all intermediate row allocations. Modern C++20 Solution (Fully Runnable) Copy C++ Code ► Compile & Run in Online C++Read more
Here is the modern C++20 implementation of the 0/1 Knapsack with 1D Backward Sweep. By reserving contiguous memory and sweeping from
capacitydown toweight[i], we eliminate all intermediate row allocations.Complexity:
See lessO(N * W)time, but auxiliary space drops fromO(N * W)to justO(W).