我正在使用 C# 和 XNA 开发 2D 高空射击游戏。我有一个我称之为“子弹”的类,需要每隔几分之一秒更新其中的许多实例。
我执行此操作的第一种方法是拥有一个通用项目符号列表,并根据需要简单地删除和添加新项目符号。但是在这样做的过程中,GC 经常启动,我的游戏有一些周期性的不稳定滞后。 (删掉了很多代码,只是想展示一个简单的片段)
if (triggerButton)
{
bullets.Add(new bullet());
}
if (bulletDestroyed)
{
bullets.Remove(bullet);
}
我的第二个也是当前的尝试是拥有一个单独的通用项目符号堆栈,当我用完一颗子弹时我将其插入,并在我需要新子弹时弹出一颗子弹(如果堆栈中有任何东西)。如果堆栈中没有任何内容,那么我会向列表中添加一个新项目符号。它似乎减少了抖动延迟,但话又说回来,有时仍然会出现一些抖动延迟(虽然我不知道这是否相关)。
if (triggerButton)
{
if (bulletStack.Count > 0)
{
bullet temp = bulletStack.Pop();
temp.resetPosition();
bullets.Add(temp);
}
else
{
bullets.Add(new bullet());
}
}
if (bulletDestroyed)
{
bulletStack.Push(bullet);
bullets.Remove(bullet);
}
所以,我知道过早的优化是万恶之源,但这是非常明显的低效率,我可以及早发现(这甚至不必担心敌人的子弹会填满屏幕)。所以我的问题是:将未使用的对象推送到堆栈会调用垃圾收集吗?引用会保持事件状态还是对象仍在被销毁?有没有更好的方法来处理更新许多不同的对象?例如,我是不是太花哨了?只遍历列表并以这种方式找到未使用的项目符号是否可以?
最佳答案
这里有很多问题,很难说。
首先是 bullet
结构还是类?如果 bullet 是一个类,那么任何时候您构造一个类,然后取消它的根(让它超出范围或将其设置为 null),您将添加 GC 需要收集的东西。
如果你要制作很多这样的东西,并且每一帧都更新它们,你可能需要考虑使用 List<bullet>
与 bullet
作为一个结构,并且 List 被预先分配(生成它的大小足以容纳所有项目符号,因此它不会在您调用 List.Add
时重新创建)。这将极大地帮助减轻 GC 压力。
另外,只是因为我需要咆哮:
So, I know premature optimization is the root of all evil, but this was very noticeable inefficiency
永远不要害怕优化您知道会导致问题的例程。如果您看到性能问题(即:您的滞后),这不再是过早的优化。是的,您不想优化每一行代码,但您确实需要优化代码,尤其是当您发现真正的性能问题时。一发现问题就立即优化比稍后尝试优化要容易得多,因为在添加大量使用 bullet
的其他代码之前,所需的任何设计更改都将更容易实现。类。
关于c# - 如何在 C# 中有效地处理许多更新对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2335883/