C#如何减少垃圾回收

时间:2016-04-03 05:54:27

标签: c# performance garbage-collection

我正在编写一个模拟,它有一个每帧调用的更新循环。在更新功能中,我有数百万个对象要更新,所以它看起来像这样。

public void Update(float deltaTime)
{
    Time += deltaTime;
    foreach (SimulationObject obj in objects.ToArray())
        obj.Update(deltaTime);
}

where objects is
List<SimulationObject> objects = new List<SimulationObject>();
and is populated at program initialization time.

你可能会看到objects.ToArray()每帧都会复制这个巨大的列表,然后副本被垃圾收集。这会给我带来巨大的性能问题。对于大约2分钟的运行,收集的垃圾达到约2G。由于某些第三方库在后台异步修改了这些对象的列表,因此我似乎无法删除ToArray()。

我想知道是否有减少垃圾收集的好方法,是避免复制还是重复使用分配的空间?

我是C#的新手,并尝试寻找答案,但未能。如果这是一个重复的帖子,我道歉。

3 个答案:

答案 0 :(得分:3)

ToArray()在这里并不是必需的,只是浪费时间和记忆。使用for循环。我会从像

这样的东西开始
for (int i = 0; i < objects.Count; i++) 
{
    SimulationObject obj = null;
    try 
    {
        obj = objects[i];
    }
    catch (ArgumentOutOfRangeException) 
    {
        // something was removed from the collection
        // we reached the end of the list
        break;
    }

    obj.Update(deltaTime)
}

此代码故意拆分obj = objects[i]obj.Update(deltaTime),以避免在Update()抛出ArgumentOutOfRangeException时中断循环。

请注意两个事实:

  • 一些对象在被添加到objects集合后会跳过第一次迭代,这实际上不应该是一个问题,因为它们的添加在设计上是异步的。
  • 某些对象可能会在从objects列表中删除后立即更新一次(当然,同时删除,但结果往往会在“)之后出现。”根据模拟情况,这种情况可能是不合需要的,可能需要一些特定的处理。

答案 1 :(得分:-1)

没有理由拨打ToArray(),因此您只需使用

即可
public void Update(float deltaTime)
{
    Time += deltaTime;
    foreach (SimulationObject obj in objects)
        obj.Update(deltaTime);
}

答案 2 :(得分:-1)

有人指出你不需要使用toArray()方法,因为它只会创建当前列表的副本。

如果我理解正确,您正在执行此操作,因为您的列表正在后台由第三方lib修改。

我认为在这种情况下你可以安全地使用Parallel.ForEach循环,因为你不是修改列表本身,只是列表中的项目。

      Float Time; // some value
      Float deltaTime; // some value
      Parallel.ForEach(objects, currObject =>
            {
                // do stuff
             Interlocked.increment(ref Time,deltaTime);
             currObject.Update(Time)
            }