我已经在使用d3d11有一段时间了,最近发现了directx调试器,发现我的程序由于许多com对象没有正确释放而到处泄漏内存。经过一番搜查和几个小时的代码分析,我已经开发出了一些方法来定位这些意外的引用计数增加的位置。
首先,所有对象都被封装在带有自定义删除器的std::shared_ptrs中,这些删除器调用它们各自的释放函数。我这样做是为了永远不必调用addref,并且第一次调用release(在删除器中)将只在对象超出作用域时调用。它看起来像这样:
// 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;
}
这是我第一次调用创建设备的函数,当我立即检查引用数量时,它显示有3个!显然,我对处理这些com对象的方式存在误解。是否有手动删除它们的方法,而不是使用后台引用计数机制?