我在用 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()
的次数是我应该调用的两倍,但是代码被包装在一个辅助类中,该类Apply()
在任何属性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 的经验更丰富,所以很明显,幕后发生了一些事情,正在创建我不知道的非托管内存。