让我们想象一下这个简单的测试程序:
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 秒的延迟是 Not Acceptable 。
只是可能不会得到支持但可以帮助我的想法:
- 我可以告诉 GC 忽略某些对象吗?
- 我可以将堆分成多个部分,以便 GC 在堆的各个部分上运行吗? (我更喜欢十倍 100 毫秒的延迟。)
最佳答案
在某些情况下,当处理大量数据在相当长的时间内无法收集时,GC 可能会很烦人 - 会有大量引用,甚至更糟:GC 实际上不可能收集太多,所以时间被浪费了!这里的一种选择是考虑使用值类型的数组等。这里的意义在于,200万个值类型的数组只是一个引用; 200 万个值对收集没有任何影响。但是,子引用仍然会产生影响,例如每行的字符串
。但它can help .
既然我提到了字符串
,另一件事就是你是否有相同底层字符组合的多个实例;例如,通过从数据库或文件加载数据。您可能会考虑在那里应用一些手动字符串驻留(不使用string.Intern
- 而是使用每个加载的字典或类似的)。这将再次减少用于收集的字符串
数量。
作为最后的想法;如果您的数据需要集合,这可能会很棘手 - 例如列表通常涉及额外的 2 个对象:列表和底层数组。将其乘以几百万,事情就会开始变得棘手。在我们的例子中,我们通过使用固定缓冲区来解决这个问题,但这是一个有点高级的主题,并且仅适用于您对数据中的项目数量有一个可预测的小“上限”的情况。列表。
关于.net - 有关如何避免客户端应用程序中 GC 延迟的建议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14810257/