【发布时间】:2011-05-01 07:22:09
【问题描述】:
在测试应用程序性能时,我遇到了一些非常奇怪的 GC 行为。简而言之,GC 甚至可以在没有运行时分配的空程序上运行!
以下应用程序演示了该问题:
using System;
using System.Collections.Generic;
public class Program
{
// Preallocate strings to avoid runtime allocations.
static readonly List<string> Integers = new List<string>();
static int StartingCollections0, StartingCollections1, StartingCollections2;
static Program()
{
for (int i = 0; i < 1000000; i++)
Integers.Add(i.ToString());
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
static void Main(string[] args)
{
DateTime start = DateTime.Now;
int i = 0;
Console.WriteLine("Test 1");
StartingCollections0 = GC.CollectionCount(0);
StartingCollections1 = GC.CollectionCount(1);
StartingCollections2 = GC.CollectionCount(2);
while (true)
{
if (++i >= Integers.Count)
{
Console.WriteLine();
break;
}
// 1st test - no collections!
{
if (i % 50000 == 0)
{
PrintCollections();
Console.Write(" - ");
Console.WriteLine(Integers[i]);
//System.Threading.Thread.Sleep(100);
// or a busy wait (run in debug mode)
for (int j = 0; j < 50000000; j++)
{ }
}
}
}
i = 0;
Console.WriteLine("Test 2");
StartingCollections0 = GC.CollectionCount(0);
StartingCollections1 = GC.CollectionCount(1);
StartingCollections2 = GC.CollectionCount(2);
while (true)
{
if (++i >= Integers.Count)
{
Console.WriteLine("Press any key to continue...");
Console.ReadKey(true);
return;
}
DateTime now = DateTime.Now;
TimeSpan span = now.Subtract(start);
double seconds = span.TotalSeconds;
// 2nd test - several collections
if (seconds >= 0.1)
{
PrintCollections();
Console.Write(" - ");
Console.WriteLine(Integers[i]);
start = now;
}
}
}
static void PrintCollections()
{
Console.Write(Integers[GC.CollectionCount(0) - StartingCollections0]);
Console.Write("|");
Console.Write(Integers[GC.CollectionCount(1) - StartingCollections1]);
Console.Write("|");
Console.Write(Integers[GC.CollectionCount(2) - StartingCollections2]);
}
}
有人可以解释这里发生了什么吗?我的印象是除非内存压力达到特定限制,否则 GC 不会运行。然而,它似乎一直在运行(和收集)——这正常吗?
编辑:我已修改程序以避免所有运行时分配。
编辑 2:好的,新的迭代,似乎 DateTime 是罪魁祸首。 DateTime 方法之一分配内存(可能是 Subtract),这会导致 GC 运行。第一个测试现在导致绝对 no 集合 - 正如预期的那样 - 而第二个导致几个。
简而言之,GC 只在它需要运行的时候运行——我只是在不知不觉中产生了内存压力(DateTime 是一个结构,我认为它不会产生垃圾)。
【问题讨论】:
标签: c# .net mono garbage-collection memory-leaks