c# - Are MakeGenericType / generic types garbage collected? -
it known in .net types not garbage collected, means if you're playing around f.ex. reflection.emit, have careful unload appdomains , on... @ least that's how used understand how things work.
that made me wonder if generic types are garbage collected, more precise: generics created makegenerictype
, let's say... example based on user input. :-)
so constructed following test case:
public interface irecursiveclass { int calculate(); } public class recursiveclass1<t> : irecursiveclass t : irecursiveclass,new() { public int calculate() { return new t().calculate() + 1; } } public class recursiveclass2<t> : irecursiveclass 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 { { gc.collect(gc.maxgeneration); gc.waitforfullgccomplete(); return gc.gettotalmemory(true); } } static void main(string[] args) { long start = memoryusage; int total = 0; (int = 0; < 1000000; ++i) { stringbuilder sb = new stringbuilder(); int j = i; (int k = 0; k < 20; ++k) // fix 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 , total {0}", total); console.writeline("current memory usage: {0}", memoryusage - start); console.readline(); } }
as can see, generic types defined 'possibly recursive', 'tail' class marks end of recursion. , ensure gc.totalmemoryusage
isn't cheating, opened task manager.
so far good. next thing did fire beast , while waiting 'out of memory' ... noticed - contrary expectations - not consuming more memory on time. in fact, shows slight drop in memory consumption in time.
can please explain this? generic types collected gc? , if so... there reflection.emit cases garbage collected?
to answer first question:
generic constructions of types not collected.
however, if construct c<string>
, c<object>
, clr generates code methods once; since reference string , reference object guaranteed same size, can safely. it's pretty clever. if construct c<int>
, c<double>
though, code methods gets generated twice, once each construction. (assuming code methods generated @ of course; methods jitted on demand; that's why called jitting.)
to demonstrate generic types not collected, instead create generic type
class c<t> { public static readonly t big = new t[10000]; }
c<object>
, c<string>
share code generated methods, each 1 gets own static fields, , fields live forever. more types construct, more memory filled big arrays.
and know why types cannot collected; have no way of knowing if going try access member of 1 of arrays @ time in future. since don't know when last array access going be, have live forever, , therefore type contains has live forever too.
to answer second question: there way make dynamically-emitted assemblies collected?
yes. documentation here:
Comments
Post a Comment