C# MakeGenericType/泛型类型是否被垃圾收集?
在.NET中,类型是不被垃圾收集的,这意味着如果你在玩f.ex。发射,你必须小心卸载AppDomains等等。。。至少我以前是这样理解事情的 这让我想知道泛型类型是否是垃圾收集的,更准确地说:泛型是用C# MakeGenericType/泛型类型是否被垃圾收集?,c#,.net,generics,types,garbage-collection,C#,.net,Generics,Types,Garbage Collection,在.NET中,类型是不被垃圾收集的,这意味着如果你在玩f.ex。发射,你必须小心卸载AppDomains等等。。。至少我以前是这样理解事情的 这让我想知道泛型类型是否是垃圾收集的,更准确地说:泛型是用MakeGenericType创建的,比方说。。。例如,基于用户输入。:-) 因此,我构建了以下测试用例: public interface IRecursiveClass { int Calculate(); } public class RecursiveClass1<T>
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();
}
}
公共接口IRecuriveClass
{
int计算();
}
公共类RecursiveClass1:IRecursiveClass
其中T:IRecursiveClass,new()
{
公共整数计算()
{
返回新的T().Calculate()+1;
}
}
公共类递归类2:IRecursiveClass
其中T:IRecursiveClass,new()
{
公共整数计算()
{
返回新的T().Calculate()+2;
}
}
公共类TailClass:IRecursiveClass
{
公共整数计算()
{
返回0;
}
}
类递归GenericsTest
{
公共静态int CalculateFromUserInput(字符串str)
{
类型tail=类型of(TailClass);
foreach(str中的字符c)
{
如果(c==0)
{
tail=typeof(RecursiveClass1)。MakeGenericType(tail);
}
其他的
{
tail=typeof(递归类2)。MakeGenericType(tail);
}
}
IRecursiveClass cl=(IRecursiveClass)Activator.CreateInstance(tail);
返回cl.Calculate();
}
静态长记忆
{
得到
{
GC.Collect(GC.MaxGeneration);
GC.WaitForFullGCComplete();
返回GC.GetTotalMemory(true);
}
}
静态void Main(字符串[]参数)
{
长启动=记忆;
int-total=0;
对于(int i=0;i<1000000;++i)
{
StringBuilder sb=新的StringBuilder();
int j=i;
for(int k=0;k<20;++k)//修复递归深度
{
如果((j&1)==1)
{
某人附加('1');
}
其他的
{
某人附加('0');
}
j>>=1;
}
total+=CalculateFromUserInput(sb.ToString());
如果((i%10000)==0)
{
WriteLine(“当前内存使用@{0}:{1}”,
i、 备忘录(启动);
}
}
WriteLine(“完成,总数为{0}”,总计);
WriteLine(“当前内存使用情况:{0}”,MemoryUsage-start);
Console.ReadLine();
}
}
如您所见,泛型类型定义为“可能是递归的”,带有一个标记递归结束的“tail”类。为了确保GC.TotalMemoryUsage
没有作弊,我还打开了任务管理器
到目前为止还不错。我做的下一件事是点燃这只野兽,在我等待“记忆不足”的时候。。。我注意到,与我的预期相反,并没有随着时间消耗更多的内存。事实上,它显示内存消耗在时间上略有下降
有人能解释一下吗?GC是否实际收集了泛型类型?如果是的话。。。是否也存在反射。发出垃圾收集的案例?回答第一个问题: 不收集类型的泛型构造 但是,如果构造
C
和C
,CLR实际上只为这些方法生成一次代码;因为对字符串的引用和对对象的引用保证大小相同,所以它可以安全地这样做。这很聪明。但是,如果构造C
和C
,则方法的代码将生成两次,每次构造一次。(当然,假设方法的代码是生成的;方法是根据需要进行jitting的;这就是为什么它被称为jitting的原因。)
要演示未收集泛型类型,请创建泛型类型
class C<T> { public static readonly T Big = new T[10000]; }
class C{public static readonly T Big=new T[10000];}
C
和C
共享为方法生成的任何代码,但每个方法都有自己的静态字段,这些字段将永远存在。构造的类型越多,这些大数组占用的内存就越多
现在你知道为什么不能收集这些类型了;我们无法知道将来是否有人试图访问其中一个阵列的成员。因为我们不知道最后一次数组访问将在何时进行,所以它们必须永远存在,因此包含它的类型也必须永远存在
回答第二个问题:是否有一种方法可以生成收集的动态发出的程序集 对。文件如下:
与代码共享或代码不共享无关,每次MakeGenericType尝试都将为metada创建新的内部CLR类,这将消耗内存。类型对象是直接在CLR代码中创建的(不是在托管代码中),每个类型对象只存在一个实例,因此您可以比较它们以获得引用相等性。CLR本身有一个对它的引用,所以它们不能被GC’ed,但在我的测试中,我确认GC可以移动它们 编辑:CLR保留的引用可能是弱引用,所以在挖掘RuntimeTypeHandle.cs源代码后,我看到了
internal bool IsCollectible()
{
return RuntimeTypeHandle.IsCollectible(GetTypeHandleInternal());
}
这很可能是错误的,考虑到Eric Lippert,您可以通过为您创建的泛型类型创建一个
WeakReference
,然后在运行GC传递后检查目标
是否为null来进行试验。也许这将有助于@ErikLippert哇,这是一个很好的答案Eric,谢谢!我发现了关于static的问题,这就是为什么我没有在类中添加static。我还是