在XNA中,处理不再需要的纹理的最佳方法是什么?

时间:2012-10-18 12:07:04

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

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

1 个答案:

答案 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中提出的设计。