我开始了一个项目,其概念是在整个游戏过程中不断重复使用相同的texture2d对象,定期重新加载新纹理。随着时间的推移,我在运行时遇到了一个坏主意:System.OutOfMemoryException
bool loadImages(string image)
{
System.Diagnostics.Debug.WriteLine("beginning loading textures " + image);
try
{
//image_a = null;
//image_o = null;
//image_o.Dispose();
//image_a.Dispose();
image_o = Content.Load<Texture2D>("images/"+image);
image_a = Content.Load<Texture2D>("images/" + image+"_a");
return true;
}
catch
{
System.Diagnostics.Debug.WriteLine("cannot load textures " + image);
image_a.Dispose();
image_o.Dispose();
}
return false; //make sure the caller loads the subsequent image
}
我猜测XNA在每次新的内容加载时都会保留过去的纹理,所以我重写了程序,而是保存一个游戏对象列表,每个对象都有自己的texture2d对象。在浏览列表后,我将处理前一个列表项的纹理对象,并将下一个列表项的纹理加载到其纹理对象。该列表只会在整个游戏中遍历一次,我只是定期进入下一个纹理集,我只会选择加载2个纹理,所以理论上应该始终只需要内存中的2个纹理。我仍然遇到内存错误。这就好像我完全不能依赖dispose方法及时释放内存中的纹理。
我加载的所有纹理都不超过125KB,我正在为windows phone 7构建这个纹理
删除不再需要的纹理的最佳方法是什么?参考代码:我应该创建新的texture2d对象,交换它们并处理原始文件吗?
答案 0 :(得分:8)
好的,首先是一些背景知识: ContentManager
缓存已加载的对象。有更详细的说明here(或here)。但基本上每个ContentManager
拥有它加载的所有内容。您不应该就该内容致电Dispose
。清理它的唯一方法是使用ContentManager.Unload
(或Dispose
)卸载缓存中的所有内容。
我猜你遇到的问题是你曾尝试Load
一个你之前称之为Dispose
的纹理 - 然后尝试使用那个处理过的纹理
虽然我认为你也可能因为ContentManager
正在存储所有那些(空的,已处置的)Texture2D
对象而耗尽内存,导致垃圾收集器无法回收它们(请参阅this answer )。
因此,如果您想沿着这条路线前进,则需要修改ContentManager
的缓存策略。如何做到这一点在this blog post中有解释。但是,当您想要从内容文件创建资产的新实例时,基本上您从ContentManager
继承,覆盖Load
并调用ReadAsset
。
最简单的方法是完全禁用缓存,而博客帖子就是一个例子。然后,您只需手动管理内容管理器加载的所有内容的生命周期(即:自己调用Dispose
)。
如果你想要更复杂的东西,也许可以在GameDev网站上查看我在this answer中提出的设计。