UE 5.8.2 Vulkan memory leak, consumed 114GB RAM and killed by OOM

Summary

Hi!

We found that on Linux Vulkan, UE 5.8.2 leaks RAM on every parallel render pass.

It was confirmed on 2 separate machines with different GPUs. Occurs in both 5.8.0 and 5.8.2.

RHIBeginParallelRenderPass() does new FVulkanDynamicRenderingInfo(). RHIEndParallelRenderPass() deletes CurrentParallelRenderPassInfo and leaves DynamicRenderingInfo behind. FVulkanParallelRenderPassInfo has no destructor. File: Engine/Source/Runtime/VulkanRHI/Private/VulkanContext.cpp.

We saw it on two Linux machines running a packaged offscreen project, with several SceneCaptures and hardware ray-traced LiDAR:

  • machine1: process grew to ~114 GB and the kernel OOM-killed it.
  • machine2: anonymous RSS grew ~1.5 GB/h. Insights + addr2line on matching debug symbols pointed at FVulkanCommandListContext::RHIBeginParallelRenderPass - operator new.

Workaround:
we tested r.Vulkan.AllowDynamicRendering=0, which reduced memory leak from about 1.5GB/h to 0.27 GB/h

What Type of Bug are you experiencing?

Simulation

Steps to Reproduce

  1. Package a Linux Vulkan build of a project that uses parallel render passes (SceneCapture / hardware ray tracing is enough).
  2. Run it offscreen for 20+ minutes (-RenderOffscreen).
  3. Watch process RSS / anonymous memory.

Optional: Insights memory trace, then addr2line on RHIBeginParallelRenderPass.

Optional: r.Vulkan.AllowDynamicRendering=0 at startup and repeat.

Expected Result

No memory leak

Observed Result

RSS climbs about 1.5 GiB/h (on 2 separate machines). Same binary on sw-perc-1 grew to ~114 GB and was OOM-killed. Trace shows RHIBeginParallelRenderPass → operator new. r.Vulkan.AllowDynamicRendering=0 drops growth to ~0.27 GiB/h. Still present in 5.8.0 and 5.8.2 source.

Affects Versions

5.8

Platform(s)

Linux

Additional Notes

Proposed fix:

From: Filip Kubicz <filip@kubicz.engineer>
Date: Fri, 11 Sep 2026 12:37:00 +0200
Subject: [PATCH] VulkanRHI: free FVulkanDynamicRenderingInfo on parallel pass end
RHIBeginParallelRenderPass heap-allocates DynamicRenderingInfo.
RHIEndParallelRenderPass only deletes CurrentParallelRenderPassInfo,
so the inner object leaks every pass.
---
 Engine/Source/Runtime/VulkanRHI/Private/VulkanContext.h | 5 +++++
 1 file changed, 5 insertions(+)
diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanContext.h b/Engine/Source/Runtime/VulkanRHI/Private/VulkanContext.h
index 0000000..1111111 100644
--- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanContext.h
+++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanContext.h
@@ -49,6 +49,11 @@
 struct FVulkanParallelRenderPassInfo
 {
 	VkRenderPass RenderPassHandle = VK_NULL_HANDLE;
 	FVulkanDynamicRenderingInfo* DynamicRenderingInfo = nullptr;
 	TArray<FVulkanPayload*> SecondaryPayloads;
 	std::atomic<int32> NumParallelContexts = 0;
+
+	~FVulkanParallelRenderPassInfo()
+	{
+		delete DynamicRenderingInfo;
+	}
 };