[GH-ISSUE #35] RTX VideoSuperResolution node leaks GPU memory per-frame — deadlocks/hangs on long video runs #30

Open
opened 2026-10-26 22:28:10 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @CharlesMcquade on GitHub (Jul 28, 2026).
Original GitHub issue: https://github.com/Comfy-Org/ComfyUI_Nvidia_VFX_Nodes/issues/35

What's happening

The RTXVideoSuperResolution node works fine for a single image or a short batch, but when you feed it a longer video (or a batch of ~60+ images) it slowly eats all available GPU memory and then hangs/deadlocks. This is the same underlying problem reported in #16 ("slowly eat up all my system memory… swapping death loop"), just seen from the GPU side.

Root cause

In __init__.py, the execute() method loops over every frame and calls sr.run(input_frame):

for j in range(batch_cuda.shape[0]):
    input_frame = batch_cuda[j]
    dlpack_out = sr.run(input_frame).image
    out_tensor[i + j: i + j + 1] = torch.from_dlpack(dlpack_out).movedim(0, -1).unsqueeze(0)

sr.run() returns a dlpack tensor. torch.from_dlpack(dlpack_out) creates a new GPU tensor that shares the dlpack's underlying storage, and that dlpack reference is reassigned on the next iteration but the previous one is never explicitly freed. Because the converted PyTorch tensor aliases the same memory, the allocator can't reclaim the storage either. Over many frames the per-frame allocations accumulate in the CUDA caching allocator and never get returned, so VRAM climbs monotonically until the node OOMs or deadlocks waiting on a CUDA call.

The .movedim().unsqueeze() ops also produce intermediate views rather than owning their own storage, so the original allocation's lifetime stays pinned to the loop.

Reproduction

  1. Open ComfyUI with the RTX nodes installed on an NVIDIA GPU.
  2. Load a video longer than ~60 frames (or generate a batch of 60+ images).
  3. Wire it into an RTX Video Super Resolution node at any scale > 1x.
  4. Run the graph and watch VRAM in nvidia-smi — it climbs steadily and never drops until the process is killed. On cards with less headroom the node simply hangs partway through.

Observed on Ubuntu 24.04, RTX 4080, 48 GB RAM (per #16) and reproduced locally on other configs.

Expected behavior

VRAM usage should stay roughly flat regardless of frame count — each frame's intermediates should be freed before the next frame is processed.

Proposed fix

Three changes to the per-frame loop:

  1. .clone() the converted tensor so the output owns its own storage and the dlpack-backed tensor can be released immediately.
  2. del the dlpack/result/out_frame references explicitly so CPython drops them on this iteration instead of waiting for scope exit.
  3. torch.cuda.empty_cache() per frame to return the now-freed blocks to the GPU.
for j in range(batch_cuda.shape[0]):
    input_frame = batch_cuda[j]
    result = sr.run(input_frame)
    dlpack_out = result.image
    out_frame = torch.from_dlpack(dlpack_out).movedim(0, -1).unsqueeze(0).clone()
    out_tensor[i + j: i + j + 1] = out_frame
    del dlpack_out, result, out_frame
    torch.cuda.empty_cache()

I've tested this locally: VRAM stays flat across 100+ frame runs where the original code OOM'd around ~60.

Related: #16. I'll open a PR with this fix shortly.

Originally created by @CharlesMcquade on GitHub (Jul 28, 2026). Original GitHub issue: https://github.com/Comfy-Org/ComfyUI_Nvidia_VFX_Nodes/issues/35 ## What's happening The `RTXVideoSuperResolution` node works fine for a single image or a short batch, but when you feed it a longer video (or a batch of ~60+ images) it slowly eats all available GPU memory and then hangs/deadlocks. This is the same underlying problem reported in #16 ("slowly eat up all my system memory… swapping death loop"), just seen from the GPU side. ## Root cause In `__init__.py`, the `execute()` method loops over every frame and calls `sr.run(input_frame)`: ```python for j in range(batch_cuda.shape[0]): input_frame = batch_cuda[j] dlpack_out = sr.run(input_frame).image out_tensor[i + j: i + j + 1] = torch.from_dlpack(dlpack_out).movedim(0, -1).unsqueeze(0) ``` `sr.run()` returns a dlpack tensor. `torch.from_dlpack(dlpack_out)` creates a **new** GPU tensor that *shares* the dlpack's underlying storage, and that dlpack reference is reassigned on the next iteration but the previous one is never explicitly freed. Because the converted PyTorch tensor aliases the same memory, the allocator can't reclaim the storage either. Over many frames the per-frame allocations accumulate in the CUDA caching allocator and never get returned, so VRAM climbs monotonically until the node OOMs or deadlocks waiting on a CUDA call. The `.movedim().unsqueeze()` ops also produce intermediate views rather than owning their own storage, so the original allocation's lifetime stays pinned to the loop. ## Reproduction 1. Open ComfyUI with the RTX nodes installed on an NVIDIA GPU. 2. Load a video longer than ~60 frames (or generate a batch of 60+ images). 3. Wire it into an `RTX Video Super Resolution` node at any scale > 1x. 4. Run the graph and watch VRAM in `nvidia-smi` — it climbs steadily and never drops until the process is killed. On cards with less headroom the node simply hangs partway through. Observed on Ubuntu 24.04, RTX 4080, 48 GB RAM (per #16) and reproduced locally on other configs. ## Expected behavior VRAM usage should stay roughly flat regardless of frame count — each frame's intermediates should be freed before the next frame is processed. ## Proposed fix Three changes to the per-frame loop: 1. **`.clone()` the converted tensor** so the output owns its own storage and the dlpack-backed tensor can be released immediately. 2. **`del` the dlpack/result/out_frame references** explicitly so CPython drops them on this iteration instead of waiting for scope exit. 3. **`torch.cuda.empty_cache()`** per frame to return the now-freed blocks to the GPU. ```python for j in range(batch_cuda.shape[0]): input_frame = batch_cuda[j] result = sr.run(input_frame) dlpack_out = result.image out_frame = torch.from_dlpack(dlpack_out).movedim(0, -1).unsqueeze(0).clone() out_tensor[i + j: i + j + 1] = out_frame del dlpack_out, result, out_frame torch.cuda.empty_cache() ``` I've tested this locally: VRAM stays flat across 100+ frame runs where the original code OOM'd around ~60. Related: #16. I'll open a PR with this fix shortly.
Author
Owner

@kingp0dd commented on GitHub (Aug 21, 2026):

Thank you

<!-- gh-comment-id:5363612672 --> @kingp0dd commented on GitHub (Aug 21, 2026): Thank you
Sign in to join this conversation.
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Comfy-Org/ComfyUI_Nvidia_VFX_Nodes#30
No description provided.