Skip to content

Vulkan: Small resources can prevent oversized memory pages from being released #820

Open

Description

@Jan-Svoboda-Tescan

Problem

The Vulkan backend’s MemoryManager can place small, long-lived resources into oversized pages allocated for large resources. After the large resource is released, the small resources prevent the entire page from being freed.

Reproduction scenario:

  1. Create a 1.5 GiB volume texture. With a 16 MiB base page size, the MemoryManager doubles the page size until it reaches 2 GiB.
  2. Create small, long-lived resources. These may occupy the remaining space in that page.
  3. Release the volume texture. The 2 GiB page remains allocated because it still contains small resources.
  4. Create a 2 GiB volume texture. It cannot fit into the partially occupied page, so another 2 GiB page is allocated.

This results in approximately 4 GiB allocated for a 2 GiB texture and a few small resources.

Expected behavior

Large resources should use isolated allocations so their backing memory can be released independently of unrelated small resources.

Proposed solution

Introduce a user-configurable size threshold for shared-page allocations:

  • Allocations at or below the threshold would use shared pages.
  • Allocations above the threshold would use separate allocations, excluded from further sharing.
  • Separate allocations would be released after resource destruction and completion of pending GPU work, independently of the shared-page reserve.

Activity

  1. MikhailGorobets commented on Oct 27, 2026

    @MikhailGorobets
    Contributor

    This is a fairly common issue with memory allocators that use suballocation. A small, long-lived allocation can prevent an entire memory block from being released, so it's not really specific to Diligent.

    For this particular use case, wouldn't it be simpler to allocate large textures directly through Vulkan (using dedicated allocations if needed) and then wrap the resulting VkImage using IRenderDeviceVk::CreateTextureFromVulkanImage()?

    This would isolate large resources without introducing additional allocation policies or configurable thresholds into the general-purpose memory manager. The only downside is that you'd need to manage the native Vulkan resource lifetime yourself.

  2. Jan-Svoboda-Tescan commented on Oct 27, 2026

    @Jan-Svoboda-Tescan
    Author

    Thank you for the quick response.

    Yes, this is the solution we currently use. However, it requires additional Vulkan specific code for resource creation and allocation, including conversions that Diligent already handles internally.

    The main complication is resource lifetime. Since CreateTextureFromVulkanImage() does not take ownership of the image, the application must destroy both the VkImage and its backing memory at a GPU-safe point.

    Attaching an RAII owner through SetUserData() does not appear sufficient by itself: releasing the Diligent texture’s final CPU reference does not necessarily mean the GPU has finished using the image. Without a way to defer that owner’s destruction, we need our own destruction queue tied to GPU completion, or explicit synchronization.

    This introduces additional resource lifetime management alongside the mechanism Diligent already provides internally.

    Is there a supported way to attach externally owned Vulkan resources to a Diligent texture and have their destruction deferred through Diligent’s existing release queues? If so, that would make this workaround considerably simpler.

  3. alken1t15 commented on Nov 5, 2026

    @alken1t15

    Hello! I'm interested in helping with this issue. Is it still relevant and available for a contributor, or is someone already working on it?

    Before implementing anything, I'd like to clarify the preferred direction. Would a change to isolate oversized allocations in the Vulkan memory manager be welcome, or would you prefer improving GPU-safe deferred destruction for externally owned resources? I saw the discussion about native allocations and the lifetime problem, and would like to agree on one concrete approach rather than introduce an unwanted allocation policy.

    If there is a suitable scope, I could start with a reproducible allocation/release scenario, then propose the implementation and validation for resource lifetime, GPU completion, and memory reclamation.

    Alternatively, are there other current, unclaimed graphics tasks you would prefer a contributor to take on? Thank you!

  4. Jan-Svoboda-Tescan commented on Nov 8, 2026

    @Jan-Svoboda-Tescan
    Author

    Hello, thank you for your interest and willingness to help. The issue is still relevant to us, and nobody on our side is currently working on it.

    We would prefer a solution within Diligent’s memory management. Using Vulkan directly already adds significant implementation overhead: our abstraction layer above Diligent needs to create textures with different data types and settings. This means duplicating and maintaining a substantial amount of texture creation and parameter conversion logic that Diligent already handles internally, rather than handling just one specific texture configuration. It also introduces Vulkan-specific code, making support for other backends more difficult.

    My experience here is mainly with the Vulkan backend, where we observed this behavior. I do not know whether other Diligent backends have similar issues.

    I also believe that reducing memory usage and managing memory more carefully would benefit Diligent users in general, especially those working with large datasets. The same allocation problem could also affect large buffers, such as those used for large point clouds or highly detailed meshes.

    Using shared pages for smaller resources and separate allocations for large resources seems like a reasonable approach to explore. It would preserve suballocation for smaller resources while preventing small, long-lived allocations from keeping oversized pages allocated. A configurable size threshold is one possible approach, but we are open to other solutions within the library.

    Of course, the implementation direction would need to be agreed with the maintainers. We would be happy to provide more details about our use case and help validate a proposed solution.

  5. alken1t15 commented on Nov 9, 2026

    @alken1t15

    Thank you for the details. I opened #826 with a proposed fix in the Vulkan memory manager.

    Allocations larger than the configured page size now get separate pages sized to the request. These pages are excluded from sharing and reclaimed independently of the reserve once the allocation has been released through the existing GPU-safe release path. Smaller allocations continue to use shared pages.

    The regression test reproduces the problem with the original implementation and passes with the fix. I also ran the related buffer and texture tests on Windows with Intel Iris Xe and NVIDIA RTX 3060 Laptop GPUs, and on Mesa llvmpipe under Linux; all 17 selected tests passed on each.

    Feedback on this approach and validation with your large-volume workload would be welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions