You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vulkan重建交换链时出现内存泄漏问题求助

Vulkan窗口反复最小化内存激增问题排查

正在学习Vulkan教程时,发现反复最小化窗口会引发内存异常:每次最小化再最大化窗口,应用内存都会激增约100MB。窗口最小化时调用vkAcquireNextImageKHR会触发VK_ERROR_OUT_OF_DATE_KHR错误,因此会执行交换链重建逻辑。

渲染循环相关代码

vkWaitForFences(_deviceManager.getDevice(), 1, &_inFlightFences[_currentFrame], VK_TRUE, UINT64_MAX);

uint32_t imageIndex;

VkResult result = vkAcquireNextImageKHR(_deviceManager.getDevice(), _swapChainManager.getSwapChain(), UINT64_MAX,
    _imageAvailableSemaphores[_currentFrame], VK_NULL_HANDLE, &imageIndex);

if (result == VK_ERROR_OUT_OF_DATE_KHR) {
    _swapChainManager.recreateSwapChain(_windowManager.getWindow(), _deviceManager.getDevice(), 
        _physicalDeviceManager.getPhysicalDevice(), _surfaceManager.getSurface(), 
        _physicalDeviceManager.getMsaaSamples(), _renderPass);
    return;
}
else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
    throw std::runtime_error("failed to acquire swap chain image!");
}

// Only reset the fence if we are submitting work
vkResetFences(_deviceManager.getDevice(), 1, &_inFlightFences[_currentFrame]);

代码执行顺序:

  • vkWaitForFences(...)
  • vkAcquireNextImageKHR(...)
  • recreateSwapChain(...)
  • vkResetFences(...)

交换链重建代码

void SwapChainManager::recreateSwapChain(GLFWwindow* window, VkDevice device, VkPhysicalDevice physicalDevice, 
    VkSurfaceKHR surface, VkSampleCountFlagBits msaaSamples, VkRenderPass renderPass)
{
    int width = 0, height = 0;
    glfwGetFramebufferSize(window, &width, &height);
    while (width == 0 || height == 0) {
        glfwGetFramebufferSize(window, &width, &height);
        glfwWaitEvents();
    }

    vkDeviceWaitIdle(device);

    cleanupSwapChain(device);

    createSwapChain(window, physicalDevice, surface, device, msaaSamples);
    createImageViews(device);

    colorResources.createResources(_swapChainExtent.width, _swapChainExtent.height,
        _swapChainImageFormat, physicalDevice, msaaSamples, device);

    depthResources.createResources(_swapChainExtent.width, _swapChainExtent.height,
        physicalDevice, msaaSamples, device);

    createFramebuffers(device, renderPass);

}

已知信息:cleanupSwapChain()负责销毁交换链占用的内存,已尝试将设备属性查询改为仅执行一次但无效;退出应用时控制台提示未在销毁VkDevice前销毁VkImages、VkImageView,还有部分VkDeviceMemory和VkBuffer(疑似独立问题)。


排查方向与修复建议

  1. 检查cleanupSwapChain()的资源销毁完整性
    确认cleanupSwapChain()是否完整销毁所有交换链关联资源:

    • 交换链本身(vkDestroySwapchainKHR)
    • 交换链图像对应的VkImageView
    • 颜色缓冲、深度缓冲的VkImage、VkImageView及绑定的VkDeviceMemory
    • 帧缓冲(vkDestroyFramebuffer)
      若colorResources和depthResources的资源未在cleanupSwapChain()中销毁,每次重建都会新增资源,直接导致内存泄漏。
  2. 修正渲染循环中的栅栏重置逻辑
    当前触发VK_ERROR_OUT_OF_DATE_KHR后直接return,vkResetFences()无法执行,会导致当前帧栅栏未重置,后续循环可能出现异常甚至资源释放问题。调整逻辑:

    if (result == VK_ERROR_OUT_OF_DATE_KHR) {
        // 重置栅栏后再重建交换链
        vkResetFences(_deviceManager.getDevice(), 1, &_inFlightFences[_currentFrame]);
        _swapChainManager.recreateSwapChain(_windowManager.getWindow(), _deviceManager.getDevice(), 
            _physicalDeviceManager.getPhysicalDevice(), _surfaceManager.getSurface(), 
            _physicalDeviceManager.getMsaaSamples(), _renderPass);
        return;
    }
    
  3. 严格遵循资源销毁顺序
    Vulkan对资源销毁顺序有严格要求:

    • 先销毁依赖资源(帧缓冲、ImageView),再销毁底层Image和DeviceMemory
    • 确保cleanupSwapChain()内的销毁顺序与recreateSwapChain()中的创建顺序完全相反:销毁帧缓冲 → 销毁颜色/深度资源 → 销毁ImageView → 销毁交换链
  4. 启用Vulkan验证层
    开启VK_LAYER_KHRONOS_validation验证层,它会精准定位未正确销毁的资源,给出具体泄漏点信息,是新手排查内存问题的关键工具。

内容的提问来源于stack exchange,提问作者Caleb Derrickson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 14:05:56