【问题标题】:In XNA, what is the best method to dispose of textures I no longer need?在 XNA 中,处理我不再需要的纹理的最佳方法是什么?
【发布时间】:2012-10-08 21:16:06
【问题描述】:

我开始了一个项目,其概念是在整个游戏中不断重复使用相同的 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 对象,交换它们,然后处理原始对象吗?

【问题讨论】:

  • 这对于您的目的可能为时已晚,但 contenttracker.codeplex.com 能够卸载单个内容项,并且它还可以处理内容项之间的内部引用的复杂问题,例如模型 ->纹理。

标签: memory-management xna textures out-of-memory


【解决方案1】:

好的,首先介绍一下背景知识:ContentManager缓存加载的对象。还有更详细的描述here(或here)。但基本上每个ContentManager 拥有它加载的一切。您不应在该内容上致电 Dispose。清理它的唯一方法是使用ContentManager.Unload(或Dispose)卸载缓存中的所有内容。

我猜您遇到的问题是您尝试 Load 一个您之前调用 Dispose 的纹理 - 然后尝试使用该已处理的纹理。

虽然我想您也可能会用完内存,因为 ContentManager 正在存储所有那些(空的、已处置的)Texture2D 对象,从而阻止垃圾收集器回收它们(请参阅this answer)。

所以,如果你想走这条路,你需要修改ContentManager的缓存策略。 this blog post 中解释了如何执行此操作。但基本上你从 ContentManager 继承,覆盖 Load,并在你想从内容文件创建资产的新实例时调用 ReadAsset。

最简单的做法是完全禁用缓存,那篇博文有一个例子。然后,您可以简单地手动管理内容管理器加载的所有内容的生命周期(即:自己调用Dispose)。

如果你想要更复杂的东西,也许可以看看我在 this answer 中提出的设计,在 GameDev 网站上。

【讨论】:

  • 当我加载内容,然后将新内容加载到同一个 texture2d 对象时,之前的内容仍在缓存中——对吗?当内容管理器决定旧的缓存纹理不再有用(如果有的话)时,我将不得不阅读。重新创建内容管理器似乎是解决琐碎问题的一种非常重要的方法。谢谢你的信息,是我阅读的时间了:)
  • 是的,当同一个 ContentManager 多次加载同一个资源时,您将收到对缓存实例的引用。
  • 感谢您的帮助。我想我可以使用卸载和加载内容方法找到一个简单的方法,遗憾的是我仍然发现自己处于同样的困境中,看来我必须像你说的那样扩展内容管理器。
  • 谢谢你的帖子,我正要搞砸我的程序!!
  • 你是说我不必对不再使用的对象调用 Dispose() 吗?
猜你喜欢
  • 2021-05-31
  • 1970-01-01
  • 2018-12-01
  • 1970-01-01
  • 2010-09-06
  • 2011-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多