在 .NET 中众所周知,类型不会被垃圾收集,这意味着如果您正在玩 f.ex。Reflection.Emit,你必须小心卸载 AppDomains 等等……至少我以前是这样理解事情是如何工作的。
这让我想知道泛型类型是否被垃圾收集,更准确地说:泛型是用创建的MakeGenericType
,比方说......例如基于用户输入。:-)
所以我构建了以下测试用例:
public interface IRecursiveClass
{
int Calculate();
}
public class RecursiveClass1<T> : IRecursiveClass
where T : IRecursiveClass,new()
{
public int Calculate()
{
return new T().Calculate() + 1;
}
}
public class RecursiveClass2<T> : IRecursiveClass
where T : IRecursiveClass,new()
{
public int Calculate()
{
return new T().Calculate() + 2;
}
}
public class TailClass : IRecursiveClass
{
public int Calculate()
{
return 0;
}
}
class RecursiveGenericsTest
{
public static int CalculateFromUserInput(string str)
{
Type tail = typeof(TailClass);
foreach (char c in str)
{
if (c == 0)
{
tail = typeof(RecursiveClass1<>).MakeGenericType(tail);
}
else
{
tail = typeof(RecursiveClass2<>).MakeGenericType(tail);
}
}
IRecursiveClass cl = (IRecursiveClass)Activator.CreateInstance(tail);
return cl.Calculate();
}
static long MemoryUsage
{
get
{
GC.Collect(GC.MaxGeneration);
GC.WaitForFullGCComplete();
return GC.GetTotalMemory(true);
}
}
static void Main(string[] args)
{
long start = MemoryUsage;
int total = 0;
for (int i = 0; i < 1000000; ++i)
{
StringBuilder sb = new StringBuilder();
int j = i;
for (int k = 0; k < 20; ++k) // fix the recursion depth
{
if ((j & 1) == 1)
{
sb.Append('1');
}
else
{
sb.Append('0');
}
j >>= 1;
}
total += CalculateFromUserInput(sb.ToString());
if ((i % 10000) == 0)
{
Console.WriteLine("Current memory usage @ {0}: {1}",
i, MemoryUsage - start);
}
}
Console.WriteLine("Done and the total is {0}", total);
Console.WriteLine("Current memory usage: {0}", MemoryUsage - start);
Console.ReadLine();
}
}
如您所见,泛型类型被定义为“可能递归”,并带有一个标记递归结束的“尾”类。为了确保GC.TotalMemoryUsage
不作弊,我还打开了任务管理器。
到目前为止,一切都很好。接下来我做的就是启动这个野兽,而我正在等待“内存不足”......我注意到它 - 与我的预期相反 -随着时间的推移并没有消耗更多的内存。事实上,它显示了内存消耗在时间上的轻微下降。
有人可以解释一下吗?泛型类型实际上是由 GC 收集的吗?如果是这样......是否也有垃圾收集的 Reflection.Emit 案例?