紧循环列表复制会产生大量垃圾

本文关键字:循环 列表 复制 | 更新日期: 2023-09-27 18:16:14

在紧凑的游戏循环中,我不希望生成任何垃圾以供GC收集并导致游戏停滞。在许多更新循环中,我的代码与以下非常相似:

List<ModifierBase> activeModsCopy;
lock (lockObj)
{
    activeModsCopy = new List<ModifierBase>(_activeMods);
}
foreach (ModifierBase mod in activeModsCopy)
{
    mod.Update(elapsedGameTime);
}

游戏以每秒60帧的速度运行,因此内存分析器报告了我创建的大量临时列表,以防止列表在迭代时被修改。实现相同结果的快速无垃圾方法是什么?

Edit:上面的代码在更新循环中运行。更新循环中没有并发性,只有一个线程通过它,但是其他线程可以从_activeMods列表中添加或删除元素。自activemodscope在update函数中创建以来,只有一个执行更新的线程可以访问它。

紧循环列表复制会产生大量垃圾

如果您从不删除列表并重用它怎么办?

private ModifierBase[] _mods = new ModifierBase[2000]; 
private int _currentModsLength = 0;

如果您希望动态增长,可以使用List<ModifierBase>(2000)

和你的更新:

public void Update()
{
   _currentModsLength = 0;
   // copy over!!
   lock(_activeMods){
      _currentModsLength = _activeMods.Length;
      for(var i = 0; i < _currentModsLength; i++){
         _mods[i] = _activeMods[i];
      }
   }
   for(var k = 0; k < _currentModsLength; k++)
      _mods[k].Update(..);
}

如果你仍然遇到延迟,这很可能不是列表复制的原因,而是你创建了许多mod并丢弃了它们。

或者,您可以切换List并使用ConcurrentBag。基本上,ConcurrentBag将线程争用最小化了一点。因此,与List不同,ConcurrentBag为每个线程提供一个列表,当您稍后需要组合列表时,它将锁定每个包微秒。

有绕过GC的不安全选项,只使用堆栈:

ModifierBase* fib = stackalloc ModifierBase[_activeMods.Length];
// do copying over
http://msdn.microsoft.com/en-us/library/cx9s2sy4.aspx