List <t> .AddRange导致短暂延迟</t>

时间:2012-09-12 15:47:04

标签: c# list xna profiling

我有一个实现ICollidable接口的实体列表。此接口用于解决实体之间的冲突。因此我的实体是:

  • 球员
  • 敌人
  • 产品
  • 瓦片

在每次游戏更新(大约60 t / s)时,我正在清除列表并根据游戏状态添加当前实体。我通过以下方式实现这一目标:

collidableEntities.Clear();
collidableEntities.AddRange(players);
collidableEntities.AddRange(enemies);
collidableEntities.AddRange(projectiles);
collidableEntities.AddRange(items);
collidableEntities.AddRange(camera.VisibleTiles);

一切正常,直到我将可见的瓷砖添加到列表中。运行游戏循环的前1-2秒会导致可见的打嗝延迟绘制(因此我可以看到渲染中的抖动)。我可以逐字地删除/添加添加图块的线条,看看是否发生抖动,所以我将其缩小到该线。

我的问题是,为什么? VisibleTiles列表大约有450-500个磁贴,因此实际上并没有那么多数据。每个图块包含Texture2D(图像)和Vector2(位置),以确定渲染的内容和位置。我要继续寻找,但是从我的头脑中,我无法理解为什么只有前1-2秒打嗝但是从那里开始顺利。

感谢任何建议。

更新

我尝试将初始容量增加到大约元素量,但没有观察到差异。

更新

根据要求,这是camera.VisibleTiles的代码

public List<Tile>
{
    get { return this.visibleTiles; }
}

3 个答案:

答案 0 :(得分:5)

每当遇到这样的性能问题时,正确的答案就是不要猜测可能的原因是什么;正确的答案是分析应用程序。有很多选择;我相信你可以在StackOverflow上找到建议。

然而,今天我感觉很幸运,所以我会忽略我刚才给你的建议,并采取疯狂的猜测。我将解释我的推理,我希望将来有助于诊断这些问题。

您描述的问题只发生一次仅在游戏开始时这一事实让我相信它不是列表本身功能所固有的任何内容,或碰撞逻辑。当然,这假设列表中的对象数量在这段时间内基本上是恒定的。如果 由其中任何一个引起,我希望它会发生每一帧

因此我怀疑垃圾收集器。您可能会在游戏开始时看到GC正在发生 - 换句话说,就在您将所有大量资产加载到内存中之后。您也可能会在代码中看似随机的点上看到它,因为您分配的任何对象理论上都可以将它从边缘推送到集合中。

我的猜测是这样的:当您加载游戏时,您创建的资产会产生大量的收集压力,但这仍然不足以触发收集。当您在游戏过程中分配对象时(在这种情况下,由于调整列表大小),它会将收集压力增加到GC最终决定激活的点,从而导致您观察到的抖动。一旦GC运行,并且所有适当的对象都已降级到正确的几代,抖动就会停止。

正如我所说,这只是一个猜测,虽然是一个受过教育的人。但是,测试很简单。在进入渲染循环之前添加对GC.Collect(2)的调用。如果我是对的,抖动应该消失。

如果你想要比这更彻底 - 我强烈推荐它 - 微软提供了一个有助于调试内存问题的工具,CLR Profiler。此工具将准确显示收集何时发生以及原因。它对XNA开发非常有用。

答案 1 :(得分:1)

GC调整每一代的尺寸可能导致1-2秒。查看相应的perf计数器,看看在第一秒内是否有大量的Gen1 / 2集合(最小化GC是游戏的有用目标)

其他随机猜测:无论出于何种原因,您的所有对象都是struct。而且非常大。因此复制它们需要很长时间。 (不会在第一秒后解释平滑)

注意:

  • 而不是合并单个列表中的项目考虑创建将避免所有复制的迭代器。
  • get profiler
  • 学习查看过程的perf计数器。有趣的类别是内存,GC,CPU,处理程序。

答案 2 :(得分:0)

您可以使用overloaded constructor for List<T>初始化具有预定义大小的列表:

var collidableEntities = new List<object>(500);