D3D12 不可避免的泄漏报告

Posted

技术标签:

【中文标题】D3D12 不可避免的泄漏报告【英文标题】:D3D12 unavoidable leak report 【发布时间】:2017-10-18 03:51:41 【问题描述】:

这个程序:

#include <d3d12.h>
#pragma comment(lib,"d3d12")

int main()

    ID3D12Debug *pDebug = NULL;
    D3D12GetDebugInterface(__uuidof(ID3D12Debug),(void**)&pDebug);
    pDebug->EnableDebugLayer();
    pDebug->Release();

    ID3D12Device *pDev = NULL;
    D3D12CreateDevice(NULL,D3D_FEATURE_LEVEL_12_1,__uuidof(ID3D12Device),(void**)&pDev);

    ID3D12DebugDevice *pDebugDevice = NULL;
    pDev->QueryInterface(&pDebugDevice);
    pDev->Release();
    pDebugDevice->ReportLiveDeviceObjects(D3D12_RLDO_DETAIL);
    pDebugDevice->Release();

在调试输出中给出:

D3D12 WARNING: Live ID3D12Device at 0x000C6BA8, Refcount: 2 [ STATE_CREATION WARNING #274: LIVE_DEVICE]
D3D12 WARNING:  Live ID3D12RootSignature at 0x000E62E8, Refcount: 0, IntRef: 2 [ STATE_CREATION WARNING #577: LIVE_ROOTSIGNATURE]
D3D12 WARNING:  Live ID3D12PipelineState at 0x0011C3C8, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #572: LIVE_PIPELINESTATE]
D3D12 WARNING:  Live ID3D12PipelineState at 0x001421D8, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #572: LIVE_PIPELINESTATE]
D3D12 WARNING:  Live ID3D12Resource at 0x00138FF8, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Heap at 0x00144DD8, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #579: LIVE_HEAP]

调试设备报告我创建的 D3D12 设备在我释放后仍然存在。我知道这确实是真的,因为调试设备本身实际上是保持 D3D12 设备存活的唯一剩余引用者,但从我的角度来看,这不是 泄漏,因为我已经正确发布了我的 D3D12 设备.这只是对我的程序输出的污染,错误地表明我的代码中有错误。

我的问题是:我真的在这里做错了吗?还是报告在 D3D12 调试设备中的工作方式是一种不良行为?关于如何解决它的任何想法?

谢谢!

【问题讨论】:

【参考方案1】:

您应该尝试使用 D3D12_RLDO_IGNORE_INTERNAL 标志来忽略那些 RefCount 为 0 但仍有 IntRef 的项目。

对于“干净关机”场景,我更喜欢使用 DXGI 调试设备报告而不是 Direct3D。

在我的 DeviceResources 实现中,我按如下方式创建 DXGI 设备:

    m_dxgiFactoryFlags = 0;

#if defined(_DEBUG)
    // Enable the debug layer (requires the Graphics Tools "optional feature").
    //
    // NOTE: Enabling the debug layer after device creation will invalidate the active device.
    
        ComPtr<ID3D12Debug> debugController;
        if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(debugController.GetAddressOf()))))
        
            debugController->EnableDebugLayer();
        
        else
        
            OutputDebugStringA("WARNING: Direct3D Debug Device is not available\n");
        

        ComPtr<IDXGIInfoQueue> dxgiInfoQueue;
        if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(dxgiInfoQueue.GetAddressOf()))))
        
            m_dxgiFactoryFlags = DXGI_CREATE_FACTORY_DEBUG;

            dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, true);
            dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, true);
        
    
#endif

    ThrowIfFailed(CreateDXGIFactory2(m_dxgiFactoryFlags, IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf())));

然后当我关闭并想要检查“泄漏”时:

#ifdef _DEBUG
    
        ComPtr<IDXGIDebug1> dxgiDebug;
        if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiDebug))))
        
            dxgiDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_FLAGS(DXGI_DEBUG_RLO_SUMMARY | DXGI_DEBUG_RLO_IGNORE_INTERNAL));
        
    
#endif

对于 Win32 应用程序,有明确的时间进行“干净退出”报告泄漏。对于 UWP 应用程序,生命周期由 PLM 控制,因此您永远不会获得“干净退出”——该进程只是在暂停后终止。对于 UWP,进行泄漏检查的最佳位置是在设备移除错误导致的“设备丢失”处理程序中。

【讨论】:

D3D12_RLDO_IGNORE_INTERNAL 标志仅删除了对内部对象的提及,但 D3D12Device 本身仍被报告为泄漏。但是,您在示例中使用的 DXGI 方法非常有效。谢谢查克!【参考方案2】:

使用 ComPtr 对象来定义您的 D3D12 对象,如 Chuck 的示例:

ComPtr<ID3D12Debug> debugController;

这是避免泄漏所必需的,并且不需要像 ComPtr 对象在其解构函数中那样执行 object->Release() 调用。

【讨论】:

以上是关于D3D12 不可避免的泄漏报告的主要内容,如果未能解决你的问题,请参考以下文章

避免、发现和消除 Cocoa 中的内存泄漏

在使用泄漏节点模块时避免节点 js 中的内存泄漏?

避免android片段中内存泄漏的最佳方法是啥

内存泄漏-原因避免和定位

Java中关于内存泄漏出现的原因以及如何避免内存泄漏(超详细版)

通过定时数据和交叉验证避免数据泄漏