c++ - 创建DirectX 10缓冲区时出现内存泄漏

标签 c++ memory-leaks directx

我有一个简单的渲染过程,该过程将一组顶点发送到几何着色器并根据该信息渲染精灵。

小应用程序的内存使用量不断增加。我使用_CrtDumpMemoryLeaks()和Visual Leak Detector进行了快速测试,它们都声称没有泄漏。

我有一个设备和一个充满顶点信息的容器:

ID3D10Device* pD3DDevice;
std::vector<SpriteVertex>* sprites;

然后在RenderSprites()方法中,我注释掉了几乎所有内容,直到泄漏停止为止(渲染也是如此;)

问题出在这里:
void DirectX10Renderer::RenderSprites()
{
    D3D10_SUBRESOURCE_DATA initData;
    initData.pSysMem = &((*sprites)[0]);

    D3D10_BUFFER_DESC bd;
    bd.Usage = D3D10_USAGE_DEFAULT;
    bd.ByteWidth = sizeof(SpriteVertex)*(numSprites);
    bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
    bd.CPUAccessFlags = 0;
    bd.MiscFlags = 0;

    // As soon as the following line is uncommented, memory starts leaking
    pD3DDevice->CreateBuffer(&bd, &initData, &m_SpriteBuffer)); // <-- this is leaking

    // the rest of the rendering code is for now commented out
}

我不确定要在每个帧上释放或删除哪些内容以阻止此情况。

最佳答案

由于其他答案已迅速提出了解决方案,而且评论也太短了(在这里是)另一种快捷方式。 您询问在运行时更新所需要的缓冲区还需要做什么:
您可以将缓冲区使用率从D3D10_USAGE_DEFAULT(仅GPU读/写)更改为D3D10_USAGE_DYNAMIC,从而使CopyResource()CopySubresourceRegion()等功能正常工作。您可以更新部分或整个缓冲区等。这会影响性能,但这是可以预料的,因为动态固有地比静态on-initialization-constant缓冲区贵。我会避免过多使用技术,而将调查的乐趣留给您。
关于开放问题的长答案
Yarrr,我很高兴,提供了新数据。和互补的朗姆 cask 。
我将尝试提供更多有关操作方法背后原因的信息,但仍会让您阅读时保持乐趣。包括Wikipedia在内的各种网站从与计算机科学相关的所有内容中汲取了乐趣。关键是使程序员直观地了解其原因,并让他分析该如何应对。就像数学中的一个简单概念一样,全等的Paraletope对初学者来说充其量只能说是神秘的,每单位时间产生大量的脏话。一百万次对我的证明,对动机的理解对正确理解有很大帮助。
内存泄漏问题是由以下事实引起的:您没有像其他人所说的那样正确地管理内存。通常,如果您有一个指向Microsoft原始内容的指针(通常是COM接口(interface)),则是否需要担心内存(当经典的C / C++指针不像new,delete,malloc等运行时)是一个很好的指示符它可以调解您与基础COM组件实例之间(或,如果可能的话,则是COM对象)之间的协商。这还包括您不认识的人开发的其他您不完全理解的API。但是,让我们谈谈COM和第一个怪癖-内存管理。实际上,这很简单,如果您采用特殊的创建/初始化方法,则它与经典的C++对象并没有真正的区别。
尽管本身没有手动分配缓冲区(手头的情况),但至少以经典的C / C++方式,任何在COM兼容接口(interface)上运行的东西(等等,我会继续讲),这些接口(interface)工作的初始空指针是,很有可能是,它在完成后依赖您调用Release()函数。Release()是我们都学会珍惜和喜爱的delete关键字的直接翻译。因此,是的,请确保通过查询各种创建函数(等同于构造函数)来遵循Microsoft的指令来管理其获取的COM对象,这些函数将用实际初始化的COM组件实例或对象的地址填充接口(interface)指针。为了将来的引用和好奇心,每个COM接口(interface)都从IUnknown派生而来,它给它提供了Release()(并要求重写它以解决继承组件的新依赖性)和其他功能,例如引用计数。
为什么对COM大惊小怪?
许多Microsoft API依赖于/基于COM(组件对象模型),这是它们实现通常的接口(interface)驱动代码的方式,在纯C++中,这些代码是由抽象类以及带有vtables和继承的快乐时光来完成的,该驱动器驱动了多态性。但是,您一定很好奇为什么不直接使用C++?您会发现,在COM刚发布时,DirectX诞生之初就已经很老了(想想1994./1995。),它是将来重申COM基本思想的自然选择。
最初,COM的开发是为了协助跨工具协作(Microsoft Office套件),或更专业的是,进程间通信。在该购物篮中,您也可以删除OLE。由此,Microsoft的软件工程师看到了进一步扩展此功能的潜力。推理认为可以以COM组件的形式创建各种资源,这些资源将响应通过COM组件首次亮相以解决问题的语言访问的标准化接口(interface)。这样,Microsoft可以将他们的许多工作封装在可扩展的格式中,为它分配各种唯一的标识符(__uuidof(),您已经发现过,这就是COM注册/跟踪所有类的方式),从而提供了一种跨语言解决方案这将使遵循COM规则的其他地方编译的内容能够以完全不同的语言工作。
实际上,它已经在其基础上发展壮大,可以提供跨流程的合作,反之亦然。它还具有各种问题,这些问题与OS开发和共享功能引起的各种开发问题有关(例如可重用的交互,打开文件对话框就是一个著名的例子)。自然,DirectX(例如ActiveX)完美地适合了这张图片。它们为操作系统提供了有关诸如游戏和模拟之类的高交互性软件的通用解决方案。
这就是为什么您在ID3D10Device中看到“I”前缀的原因,该前缀代表Interface,特别是针对COM组件的一个前缀,它解决了实际的实现。您通过需要GUID标识的统一函数调用(指向接口(interface)指针的指针)连接COM组件的实例,然后根据您提供的描述取回工作的D3D10设备。这就是为什么还要提供实际的指针作为LPVOID的原因(或者基本上是说这里是字节,必须要做的事情)。如果您的用法正确,则基础实现将为您正确解决此问题,并使您的接口(interface)指针起作用。基本上,获取功能正常的COM实例的查询使引用随AddRef()一起上升,而随着Release()函数而下降。类似于保留释放的概念。
而且通常将所有这些组件放入一堆DLL中,这些DLL已“呈现”以进行正确的版本控制而没有问题。而且您得到了不错的API实现,说实话,这还不错。其实很漂亮。
.NET和COM之间的“差异”
如今,它的一些主要功能可能使那些一眼意识到.NET的人感到困惑,但是应该指出,COM是.NET的前身(因此,几乎只是暂时的前身,它们共享的很少,令人惊讶)。 (自2000年以来一直在这里)。还应该注意的是,COM的今天的功能集有些偶然,而.NET框架是经过有意开发的,旨在为所有使用Windows的开发人员提供跨语言标准平台。在最初实现后,COM的潜力就显现出来了。 .NET是由潜力和需求驱动的。
对于像Windows这样广泛使用的平台,这样的决定是合乎逻辑的,您拥有许多精通不同语言的开发人员。通过制作符合CLS的组件,您可以享受以许多不同的.NET语言编译的许多解决方案-缩短了开发时间,并实际上从性能上受益。例如,一些使用C#(。NET语言)的数学函数可解析为实际使用C / C++编写的外部函数,速度更快(pow()是此示例)。
更重要的是,.NET不仅超越了COM(如果他们必须“竞争”,那几乎是毫无意义的),而且它们在做事方式上也有根本不同。这就是Microsoft采取各种方式将COM与.NET连接,将其包装而不会损坏.NET框架的核心体系结构的原因。
如果您不了解它,那么这里只是个简单的介绍,简化为使其易于使用,整本书都以COM主题撰写。使用它需要更简单,直观的理解。希望对您有所帮助,并祝您编程愉快。并尽量不要在render函数中创建内容,特别是如果您负责它的内存管理时。

关于c++ - 创建DirectX 10缓冲区时出现内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10044638/

相关文章:

c# - Protobuf-net 序列化/反序列化 c# vs Linux c++

c++ - 奇怪的内存泄漏

c++ - cuda统一内存泄漏

c++ - 将 ogre3d 与全息透镜集成

c++ - Asm CALL 指令 - 它是如何工作的?

java - 在jsp中包含一个cpp文件

c++ - 链表中的搜索函数 - C++

JavaFX:阶段和 Controller 生命周期...内存管理

c++ - 将 DirectX SDK 代码转换为新的 Windows 8.1 SDK 代码

C++ DirectX 无法读取内存