c++ - D3D11 不知从哪里增加了引用计数?

标签 c++ com c++11 directx direct3d11

我使用 d3d11 已经有一段时间了,在发现 directx 调试器之后,我最近发现我的程序从所有未正确释放的 com 对象处泄漏内存。在四处窥探和盯着代码看了几个小时之后,我开发了一些方法来隔离我在何处获得这些意外增加的引用计数。

首先,所有对象都包装在 std::shared_ptr 中,带有调用各自释放函数的自定义删除器。我这样做是为了永远不必调用 addref,并且删除器中的第一个释放调用只会在对象超出范围时调用。它看起来像这样:

// in D3D11Renderer.h
...
// declaration
std::shared_ptr<ID3D11Device *> m_Device;
...

// after call to ID3D11CreateDeviceAndSwapChain
m_Device.reset(device, [](ID3D11Device * ptr){ptr->Release();})

问题是 api 调用中的某些随机函数只会随机增加引用计数,希望我稍后必须处理它。

我发现在诊断中有用的是一个看起来像这样的函数:

template <typename T>
int getRefCount(T object) 
{
    object->AddRef();
    return object->Release();
}

其中,只是递增和递减计数以获得该对象的当前引用计数。使用这个,我发现,就在调用自定义删除器中的发布之前,有 10 个未完成的引用指向我创建的 1 个 ID3D11Device。出于好奇,我慢慢回溯,在整个程序中一直调用这个函数,直到我最初创建它的地方。有趣的是,就在我第一次创建对象之后(甚至在 shared_ptr 取得所有权之前),未完成引用的数量已经是 3!这在此之后立即发生。

result = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, &featureLevel, 1, 
                           D3D11_SDK_VERSION, &swapChainDesc, &swapChain, &device, NULL, &deviceContext);
    if(FAILED(result))
    {
        return false;
    }

这是我第一次调用创 build 备的任何此类函数,当我检查之后有多少个 refs 时,它说 3!很明显,我误解了这些 com 对象的处理方式。有什么方法可以让我手动删除它们,而不是在幕后使用 ref 计数废话吗?

最佳答案

每次您创建缓冲区或着色器或任何依赖于设备的对象时,该对象都可能包含对设备的引用,因此会增加其引用计数以确保它在仍在使用时不会被删除。

听起来您的方法总体上可能很有效,因为您基本上会在代码中保留对设备的一个引用以阻止它被删除,并在所有内部引用都消失后释放它。然而,d3d 仍将执行它自己的引用计数,因此当您释放对每个其他相关对象的每个引用时,引用计数只会降至零。即使只是创建交换链和设备也会创建后台缓冲区等,这可能需要维护对设备的引用。

我尝试了一段时间同样的想法......最后发现它更容易

#include <atlbase>

然后使用

CComPtr<ID311Device> m_Device

因为这几乎正是该类的设计目的,并且它比 std::shader_ptr 更轻量级,因为对象中已经有一个引用计数器,因此无需保留一个单独的引用计数器。

关于c++ - D3D11 不知从哪里增加了引用计数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13644380/

相关文章:

c++ - .gdbinit 文件丢失

c++ - 为什么 QObject::findChildren 返回具有公共(public)基类的 child ?

c++ - 为什么这里会出现字节顺序问题?

c++ - 实现覆盖图标?

c# 如何将 IntPtr 转换为结构?

c++ - 什么时候应该在模板函数中使用 typename?

c++ - 如何正确初始化类值成员?

.net - COM 字符串 (BSTR) 和 .NET 字符串有什么区别?

c++ - 使用模板在编译时填充运行时数据

c++ - C++0x 中 allocator_traits<T> 的目的是什么?