2

I conducted the following experiment
pch.h

#pragma once
#include <Unknwn.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <d3d12.h>
#include <dxgi1_4.h>

main.cpp

#include "pch.h"


using namespace winrt;
using namespace Windows::Foundation;

int main()
{
    init_apartment();
    com_ptr<ID3D12Debug> debugController;
    winrt::check_hresult(D3D12GetDebugInterface(guid_of<ID3D12Debug>(), debugController.put_void()));
    debugController->EnableDebugLayer();
    com_ptr<IDXGIFactory4> dxgiFactory;
    check_hresult(CreateDXGIFactory1(guid_of<IDXGIFactory4>(), dxgiFactory.put_void()));
    com_ptr<IDXGIAdapter1> dxgiAdapter{ nullptr };
    check_hresult(dxgiFactory->EnumAdapters1(0, dxgiAdapter.put()));
    com_ptr<ID3D12Device> device;
    check_hresult(D3D12CreateDevice(dxgiAdapter.get(), D3D_FEATURE_LEVEL_11_0, guid_of<ID3D12Device>(), device.put_void()));
    com_ptr<ID3D12Device4> device4 = device.as<ID3D12Device4>();
    

    //Block 1
    //This block leads to memory leak
    {
        com_ptr<ID3D12GraphicsCommandList> commandList;
        device4->CreateCommandList1(0, D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_LIST_FLAG_NONE, guid_of<ID3D12GraphicsCommandList>(), commandList.put_void());
        while (true)
        {
            com_ptr<ID3D12CommandAllocator> commandAllocator;
            device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, guid_of<ID3D12CommandAllocator>(), commandAllocator.put_void());
            commandList->Reset(commandAllocator.get(), nullptr);
            commandList->Close();
            commandAllocator->Reset();
        }
    }
    
    //Block 2
    //This block act normally
    {
        com_ptr<ID3D12GraphicsCommandList> commandList;
        while (true)
        {
            com_ptr<ID3D12CommandAllocator> commandAllocator;
            device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, guid_of<ID3D12CommandAllocator>(), commandAllocator.put_void());
            com_ptr<ID3D12GraphicsCommandList> commandList;
            device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator.get(), nullptr, guid_of<ID3D12GraphicsCommandList>(), commandList.put_void());
            commandList->Close();
            commandAllocator->Reset();
        }
    }

    //Block 3
    //This block represents most common workflow
    {
        com_ptr<ID3D12GraphicsCommandList> commandList;
        device4->CreateCommandList1(0, D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_LIST_FLAG_NONE, guid_of<ID3D12GraphicsCommandList>(), commandList.put_void());
        com_ptr<ID3D12CommandAllocator> commandAllocator;
        device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, guid_of<ID3D12CommandAllocator>(), commandAllocator.put_void());
        while (true)
        {
            commandList->Reset(commandAllocator.get(), nullptr);
            commandList->Close();
            commandAllocator->Reset();
        }
    }
    

}

Executing Block 1 (by commenting the other blocks) leads to horrible memory leak Block 1 leads to memory leak

But memory usage remains almost unchanged when executing Block 2 and Block 3 Block 2 execution result Block 3 execution result

Block 1 recreates D3D12CommandAllocator in every frame.
Block 2 recreates D3D12CommandAllocator and D3D12CommandList in every frame.
Block 3 represents most common workflow.

But why Block 1 leads to memory leak.

Xeon-J
  • 162
  • 1
  • 7
  • Could you please tell me what project you are using? Is it a **DirectX 12 App(Universal Windows-C++/CX)**? – YanGu Feb 25 '21 at 09:13
  • I am using Windows Console Application(C++/WinRT) – Xeon-J Feb 25 '21 at 10:11
  • I can’t reproduce the memory leak with your code. Could you please provide us a sample for testing by using OneDrive or GitHub? – YanGu Feb 26 '21 at 08:15
  • Sure. I upload a video on onedrive https://1drv.ms/v/s!AvBqXpGudhIpi_1AFhviuFpN9I8J5g?e=gDz2bo And codes on github https://github.com/cjj19970505/CommandListMemoryTest – Xeon-J Feb 27 '21 at 02:33
  • But if you cant reproduce it, maybe it's a driver issue? I am using Surface Pro 7+ i7 1165g7 with intel iris Xe Grahpics driver 27.20.100.8853 – Xeon-J Feb 27 '21 at 02:38
  • Yes, I haven’t a Surface Pro 7+ i7 to test the sample. I will consult other engineers for you case. – YanGu Mar 01 '21 at 09:40
  • Recently I found that using Warp adapter eliminate the memory leak issue. So it might be a driver bug. – Xeon-J Mar 01 '21 at 13:19
  • The code in Block 1 is a pretty bizarre corner case, as they’re repeatedly resetting without ever actually recording or executing any GPU commands. – YanGu Mar 02 '21 at 07:51
  • Memory leak still happened if you try to record something on CommandList. I had a application that creating and destroying commandlists and allocators every frame for some special use case. Since the commandlist and allocator creation are "heavier" than I thought, I try to create a CommandListPool and CommandAllocatorPool. When I completed the CommandListPool, I found there is memory leak issue. But after I completed CommandAllocatorPool, the issue is amazingly gone. That's how I found the issue. – Xeon-J Mar 02 '21 at 14:29

0 Answers0