C# 确定XNA博弈滞后

C# 确定XNA博弈滞后,c#,garbage-collection,xna,C#,Garbage Collection,Xna,我目前正在使用C#&XNA创建一个塔防游戏。游戏在一段时间内运行良好且流畅,但在玩了一段时间后(在足够多的敌人/塔/子弹产生后),游戏似乎以指数级速度减慢。即使清除了所有实例,延迟仍然存在 起初,我认为这可能与垃圾收集有关(也许确实如此),但为了测试它,我编写了析构函数,以便在对象被收集并且一切看起来都很好(所有对象都被收集)时打印。所以我很好奇,是否有人有过XNA滞后的经验,以及可能的原因 编辑:这是针对PC的我用两件事来检查性能 1) App Hub有一个可用于帮助您确定需要改进的方面 2)

我目前正在使用C#&XNA创建一个塔防游戏。游戏在一段时间内运行良好且流畅,但在玩了一段时间后(在足够多的敌人/塔/子弹产生后),游戏似乎以指数级速度减慢。即使清除了所有实例,延迟仍然存在

起初,我认为这可能与垃圾收集有关(也许确实如此),但为了测试它,我编写了析构函数,以便在对象被收集并且一切看起来都很好(所有对象都被收集)时打印。所以我很好奇,是否有人有过XNA滞后的经验,以及可能的原因


编辑:这是针对PC的

我用两件事来检查性能

1) App Hub有一个可用于帮助您确定需要改进的方面

2) 这个现在有点旧了,但是


更新:我也忘了。它还涉及到一些事情。

游戏循环时间是否增加了?将秒表添加到更新循环和绘制循环的起点和终点。如果速度增加,请尝试排除(移动stopwatch.Start()和/或stopwatch.Stop()),直到找到导致速度减慢的原因。如果它没有增加,它是由其他原因引起的

尝试将此行添加到代码中:

SpriteBatch.DrawInt64(Font, GC.GetTotalMemory(false) / 1000 /* in kilobytes */,
POSITION, Color.White, 0f);
(DrawInt64/32是spritebatch的一个非常有用的扩展,它允许您在不生成垃圾的情况下绘制数字,可在此处找到:。或者只需使用DrawString和.ToString()


每次显示的数量减少时,垃圾收集都会运行。

如果您担心垃圾收集会影响性能,您可以学习使用的最佳工具之一是。此实用工具允许您分析程序执行的堆分配,以便您能够准确地识别哪些方法正在生成垃圾。请记住,有很多不明显的东西可以分配到堆上:连接字符串、使用枚举键索引字典、闭包、委托等。即使是以每秒60多帧的速度每帧生成一次的少量垃圾,在适当的情况下也可以很快加起来

也就是说,你所描述的对我来说并不是垃圾收集的问题。GC通常足够快,即使是在一个完整的收集过程中,也只会导致一些帧被删除——换句话说,您会经常注意到一个小的、令人讨厌的抖动,但不会持续减速

(注意:这仅适用于PC,与其他XNA平台相比,PC具有非常复杂的GC。)


您应该尝试在代码中附加一个分析器,以确定哪些方法需要最长的时间才能完成;如果您的问题与GC无关,这可能会提供信息。在过去,我使用过,尽管我对他们的一些最新版本有一些问题。你可以试试那个,或者你可以在谷歌上四处寻找替代方案。

你不会忘了解开事件挂钩吧?在下面的示例中,我将4个精灵添加到一个列表中,每个精灵从游戏中挂钩一个事件。然后,我移除一个精灵并引发事件

在这种情况下,所有4个精灵仍然处于活动状态,并且因为在游戏中仍然存在对他们的引用而使他们的事件升高

只是想一想,如果你正在为你的游戏对象使用事件,你可能会让它们都静止不动

class Game
{
  public event EventHandler SomeEvent;
  List<Sprite> sprites;

  public Game()
  {
    sprites = new List<Sprite>();
    sprites.Add(new Sprite(this));
    sprites.Add(new Sprite(this));
    sprites.Add(new Sprite(this));
    sprites.Add(new Sprite(this));

    sprites.RemoveAt(0);

    EventHandler temp = SomeEvent;
    if (temp != null)
    {
        temp(this, EventArgs.Empty);
    }
  }

  static void Main(string[] args)
  {
      Game newProgram = new Game();
  }



  class Sprite
  {
      public Sprite(Game gameReference)
      {
          gameReference.SomeEvent += new EventHandler(gameReference_SomeEvent);
      }

      void gameReference_SomeEvent(object sender, EventArgs e)
      {
          Debug.WriteLine("Event");
      }    
  }
类游戏
{
公共事件事件处理程序SomeEvent;
列出精灵;
公共游戏()
{
sprites=新列表();
添加(新精灵(此));
添加(新精灵(此));
添加(新精灵(此));
添加(新精灵(此));
精灵。移除(0);
EventHandler temp=SomeEvent;
如果(温度!=null)
{
temp(这个,EventArgs.Empty);
}
}
静态void Main(字符串[]参数)
{
Game newProgram=新游戏();
}
雪碧
{
公共精灵(游戏参考)
{
gameReference.SomeEvent+=新事件处理程序(gameReference\u SomeEvent);
}
void gameReference\u SomeEvent(对象发送方,事件参数e)
{
Debug.WriteLine(“事件”);
}    
}

建议:更好(总体)问题可能是->我能做些什么来确定延迟发生在哪里?似乎这可能是由许多不同的事情造成的,我们必须看到您的许多代码来确定延迟问题的根源。有太多的代码需要简单地查看。我要求更多的理论解决方案或延迟的可能原因。目前没有这里不涉及网络,所以这不应该是一个问题。我建议打印(到调试日志文件或其他文件)当您进入和退出较大的子例程/可疑区域时,会有一个时间戳。通过这种方式,您可以看到您损失的时间,并向内解决问题创建一个堆转储可能有助于确定问题,如果您获得多个堆转储并对其进行比较,您可能会看到问题的症结所在。此链接可能会有所帮助:是是在360、PC还是WP7上?确定是否正在发生垃圾收集的更好方法是使用GC.CollectionCount()。这将允许您查看每一代的收集时间。第0代收集可能不是什么大问题;第1代和第2代收集在性能方面更受关注。