Собирается ли мусор MakeGenericType / generic types?
в .NET хорошо известно, что типы не собираются в мусор, что означает, что если вы играете с f.бывший. Отображение.Emit, вы должны быть осторожны, чтобы выгрузить AppDomains и так далее... По крайней мере, так я раньше понимал, как все устроено.
это заставило меня задуматься, если общие типы are собранный мусор, если быть более точным: дженерики, созданные с 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
не обманывает, я также открыл Диспетчер задач.
пока все хорошо. Следующее, что я сделал, это запустил этого зверя, и пока я ждал и "из памяти"... Я заметил, что это было - вопреки моим ожиданиям - не потребляя больше памяти с течением времени. На самом деле, он показывает a небольшое падение потребления памяти во времени.
может кто-нибудь объяснить это? Действительно ли универсальные типы собираются GC? И если так... есть также отражение.Выбрасывать дела, которые собирают мусор?
1 ответов
чтобы ответить на ваш первый вопрос:
общие конструкции типов не собираются.
однако, если вы построите C<string>
и C<object>
, среда CLR фактически генерирует код для методов только один раз; поскольку ссылка на строку и ссылка на объект гарантированно имеют одинаковый размер, это можно сделать безопасно. Это довольно умно. Если вы построите C<int>
и C<double>
хотя, код для методов создается дважды, один раз для каждого строительство. (Предполагая, что код для методов генерируется вообще, конечно; методы jitted по требованию; вот почему его называют jitting.)
чтобы продемонстрировать, что универсальные типы не собираются, вместо этого создайте универсальный тип
class C<T> { public static readonly T Big = new T[10000]; }
C<object>
и C<string>
поделитесь любым кодом, созданным для методов, но каждый из них получает свои собственные статические поля, и эти поля будут жить вечно. Чем больше типов вы создадите, тем больше памяти будет заполнено этими большими матрицы.
и теперь вы знаете, почему эти типы не могут быть собраны; у нас нет способа узнать, если кто-то попытается получить доступ к члену одного из этих массивов в любое время в будущем. Поскольку мы не знаем, когда будет последний доступ к массиву, они должны жить вечно, и поэтому тип, который его содержит, тоже должен жить вечно.
чтобы ответить на ваш второй вопрос: есть ли способ, чтобы динамически выдаются сборки, которые собираются?
да. Документация здесь: