gpt4 book ai didi

c# - XNA 4.0/C# 中与纹理相关的内存泄漏

转载 作者:太空宇宙 更新时间:2023-11-03 16:13:20 25 4
gpt4 key购买 nike

我在用 C# 编写的 XNA 4.0 应用程序中发现内存泄漏。该程序需要运行很长时间(几天),但在几个小时的过程中内存不足并崩溃。打开任务管理器并观察内存占用情况,每秒都会有 20-30 KB 的内存分配给我的程序,直到用完。我相信当我设置 BasicEffect.Texture 属性时会发生内存泄漏,因为这是最终引发 OutOfMemory 异常的语句。

该程序将大约 300 个大型 (512px) 纹理作为 Texture2D 对象存储在内存中。纹理不是正方形,甚至不是 2 的幂 - 例如可以是 512x431 - 一侧总是 512px。这些对象仅在初始化时创建,因此我非常有信心这不是由动态创建/销毁 Texture2D 对象引起的。一些界面元素创建它们自己的纹理,但只在构造函数中创建,并且这些界面元素永远不会从程序中删除。

我正在渲染纹理贴图三角形。在使用三角形渲染每个对象之前,我将 BasicEffect.Texture 属性设置为已创建的 Texture2D 对象,并将 BasicEffect.TextureEnabled 属性设置为 。我使用 BasicEffect.CurrentTechnique.Passes[0].Apply() 在每个调用之间应用 BasicEffect - 我知道我正在调用 Apply() 是我应有的两倍,但代码包含在辅助类中,只要 BasicEffect 的任何属性发生变化,该辅助类就会调用 Apply()

我正在为整个应用程序使用单个 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 应用程序,因此我每秒调用 Draw 方法 60 次,该方法呈现我所有的各种界面元素。这意味着我可以每帧绘制 100-200 个纹理,绘制的纹理越多,内存用完的速度就越快,即使我没有在更新/绘制的任何地方调用 new循环。与 DirectX 相比,我对 OpenGL 更有经验,所以很明显在幕后发生了一些事情,它正在创建我不知道的非托管内存。

最佳答案

我能给你的唯一建议是将你的纹理分组到图集而不是一个接一个。如果您每帧渲染大量纹理,它将加快您的渲染时间并减少 GPU 的负载。这样做的原因是因为 GPU 将不必如此频繁地交换纹理来渲染,这是一项昂贵的操作。我正在使用我对 OpenGL 的了解,但我的猜测是 XNA 基于 DirectX,我假设它们以类似的方式加载纹理(除非您使用的是允许您使用 OpenGL 的 Monogame)

也就是说,您没有提供太多信息。内存泄漏可能来自纹理切换,但也可能来自其他地方。您的大部分内存都被纹理占用,这可能就是为什么您在那里而不是其他地方发生崩溃的原因。我猜这里发生了一些事情:

  • 垃圾收集器的工作速度不够快,无法收集渲染函数内分配的所有 RAM
  • 您的代码中的其他地方存在内存泄漏,而它却出现在这里

再一次,如果我对你的代码知之甚少,很难弄清楚这里有什么。但尽我所能,我有一些建议给你:

  • 运行您的代码并查看您是如何引用事物的。确保在类和结构中没有任何临时引用。如果您使用某物并将其传递给不同的类并在以后将其视为“丢弃”,则很有可能有人仍在持有该对象,以防止其被删除
  • 搜索解决方案中的所有"new"关键字。如果你有一些东西经常使用“new”关键字,这可能是一个巨大的内存泄漏,因为它在堆中创建了大量的对象。垃圾收集器应该把它们捡起来,但我不会说我非常信任垃圾收集器。最坏的情况是垃圾收集器没有足够频繁地出现以处理此内存泄漏。
  • 寻找减小纹理尺寸的方法。 Atlasing 是一种解决方案,可以减少将每个纹理打包到它自己的 Texture2D 中的开销。这可能需要更多的工作,因为您将不得不在一个交换来自同一文件的纹理的系统中工作,但在您的情况下,这可能是值得的。
  • 如果您确信 XNA 中存在问题,请尝试名为 Monogame 的不同实现。它遵循与 XNA 完全相同的结构,但由社区维护。因此,您正在使用的库的核心内容已被重写,并且很有可能破坏您的堆的任何内容都已得到修复。

我给你的建议?如果您真的熟悉 OpenGL 并且您正在做的事情相当简单,那么我会检查 OpenTK。它是一个薄链接层,采用 OpenGL 并将其“移植”到 C# 中。所有命令都完全相同,您可以灵活地使用整个 .NET 库来解决所有多余的问题。

希望对您有所帮助!

关于c# - XNA 4.0/C# 中与纹理相关的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16702596/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com