关于如何避免客户端应用程序中的GC延迟的建议

时间:2013-02-11 10:28:00

标签: .net garbage-collection

让我们想象一下这个简单的测试程序:

static void Main(string[] args)
{
    var length = 30000000;
    var c = new List<object>();
    for (int i = 0; i < length; i++)
    {
        c.Add(new object());
    }
    var start = DateTime.Now;
    GC.Collect();
    GC.WaitForFullGCComplete();
    Console.WriteLine("GC took " + (DateTime.Now - start).TotalMilliseconds + " ms");
    Console.ReadKey();
}

在我的计算机上(Framework 4.0,x64),输出约为1.4秒,而样本消耗约1GB的RAM。

问题:有没有办法加速垃圾收集?任何最佳做法?客户端应用程序中大约1GB的内存消耗很多,但仍然相当合理。但在我的情况下,延迟时间> 1秒是不可接受的。

可能不会支持但可以帮助我的想法:

  • 我可以告诉GC忽略某些对象吗?
  • 我可以将堆分成多个部分,以便让GC运行在堆的某些部分上。 (我会优先延迟十次100毫秒。)

2 个答案:

答案 0 :(得分:4)

在某些情况下,当处理大量无法收集的数据相当长的时间时,GC可能很烦人 - 会有很多引用,甚至更糟:GC实际上不太可能收集太多,所以浪费时间!这里的一个选项可以是考虑使用值类型的数组等。这里的意义是200万个值类型的数组只是一个引用; 200万对收集没有任何影响。但是,子引用仍会产生影响,例如每行string个。但它can help

由于我提到了string,所以另外要看的是你是否有多个相同的基础字符组合的实例;例如,通过从数据库或文件加载数据。您可以考虑在那里应用一些手动字符串实习(使用string.Intern - 但是每个加载字典或类似字典)。这将再次减少正在收集的string个数。

最后的想法;如果您的数据需要集合,那可能会很棘手 - 例如,列表通常涉及额外的2个对象:列表和基础数组。乘以几百万,事情就变得棘手了。在我们的情况下,我们通过使用固定缓冲区解决了这个问题,但这是一个高级主题,并且只有在您对项目数量有可预测且小的“上限”时才适用。列表。

答案 1 :(得分:0)

您的测试完全是人为的 - 实际上,您不会明确等待GC在您的应用程序中完成。

但是,如果您有一些时间关键的代码段,那么您可以disable GC temporarily