【发布时间】:2013-05-18 03:27:27
【问题描述】:
我在用 C# 编写的 XNA 4.0 应用程序中发现了内存泄漏。该程序需要运行很长时间(几天),但它会在几个小时内耗尽内存并崩溃。打开任务管理器并观察内存占用情况,每隔一秒就会为我的程序分配另外 20-30 KB 的内存,直到它用完为止。我相信当我设置BasicEffect.Texture 属性时会发生内存泄漏,因为那是最终引发OutOfMemory 异常的语句。
该程序有大约 300 个大 (512px) 纹理作为 Texture2D 对象存储在内存中。纹理不是正方形,甚至不是 2 的幂 - 例如可以是 512x431 - 一侧总是 512px。这些对象仅在初始化时创建,因此我相当确信它不是由动态创建/销毁 Texture2D 对象引起的。一些界面元素创建自己的纹理,但只在构造函数中创建,并且这些界面元素永远不会从程序中删除。
我正在渲染纹理映射的三角形。在使用三角形渲染每个对象之前,我将BasicEffect.Texture 属性设置为已创建的Texture2D 对象,并将BasicEffect.TextureEnabled 属性设置为true。我在每个调用之间使用BasicEffect 和BasicEffect.CurrentTechnique.Passes[0].Apply() - 我知道我调用Apply() 的次数是我应该调用的两倍,但是代码被包装在一个调用@987654331 的辅助类中@ 每当BasicEffect 的任何属性发生变化时。
我为整个应用程序使用了一个 BasicEffect 类,我更改了它的属性并在渲染对象时调用 Apply()。
首先,更改BasicEffect.Texture 属性并多次调用Apply() 是否会导致内存泄漏?
其次,这是渲染具有不同纹理的三角形的正确方法吗?例如。使用单个 BasicEffect 并更新其属性?
此代码取自帮助程序类,因此我已删除所有绒毛,仅包含相关的 XNA 调用:
//single BasicEffect object for entire application
BasicEffect effect = new BasicEffect(graphicsDevice);
// loaded from file at initialization (before any Draw() is called)
Texture2D texture1 = new Texture2D("image1.jpg");
Texture2D texture2 = new Texture2D("image2.jpg");
// render object 1
if(effect.Texture != texture1) // effect.Texture eventually throws OutOfMemory exception
effect.Texture = texture1;
effect.CurrentTechnique.Passes[0].Apply();
effect.TextureEnabled = true;
effect.CurrentTechnique.Passes[0].Apply();
graphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices1, 0, numVertices1, indices1, 0, numTriangles1);
// render object 2
if(effect.Texture != texture2)
effect.Texture = texture2;
effect.CurrentTechnique.Passes[0].Apply();
effect.TextureEnabled = true;
effect.CurrentTechnique.Passes[0].Apply();
graphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices2, 0, numVertices2, indices2, 0, numTriangles2);
这是一个 XNA 应用程序,因此我每秒调用 60 次 Draw 方法,它会呈现我所有的各种界面元素。这意味着我可以每帧绘制 100-200 个纹理,并且绘制的纹理越多,内存耗尽的速度就越快,即使我没有在更新/绘制循环中的任何地方调用 new。与 DirectX 相比,我对 OpenGL 的经验更丰富,因此很明显,幕后发生了一些事情,正在创建我不知道的非托管内存。
【问题讨论】:
-
你能给 Visual Studio 的项目提供这个问题吗?我没有什么想法可以尝试解决这个问题。
-
不幸的是,该项目是基于研究的,并且太大而无法提取一小块,所以我无法分发它。
-
不要试图猜测这里发生了什么。学习使用CLR Profiler 工具。它会准确地告诉你是什么导致内存被分配。
-
实际上,您的代码看起来不错。我也会这样做。问题可能在 XNA 内部很深。如果找不到解决方案,可以尝试不时重新创建效果。绝对不是一个好的解决方案,但如果可行的话......
-
正如科尔坎贝尔所说;使用 CLR 分析器。我想补充一点,从文件中加载纹理意味着你必须自己处理它们。如果不这样做,并且多次加载它们,您将遇到 OutOfMemoryException。
标签: c# memory-leaks xna directx texture2d