c# - GC Behavior Inconsistent Between 32-bit and 64-bit Applications -
i have noticed inconsistent behavior gc when compiling console applications under both 32-bit , 64-bit in .net 4.0 using vs 2013.
consider following code:
class test { public static bool finalized = false; ~test() { finalized = true; } }
and in main()
...
var t = new test(); t = null; gc.collect(); gc.waitforpendingfinalizers(); if (!test.finalized) throw new exception("oops!");
when running in 64-bit (debug) mode works every time without fail; however, running in 32-bit mode cannot force object collected (even if create more objects , wait period of time, have tried).
does have ideas why is? it's causing me trouble when trying debug code must deal releasing unmanaged proxy data 32-bit version of assemblies. there's lot of objects in 32-bit mode sit there until long time later (no in 64-bit).
i'm trying debug in 32-bit mode, finalizers not getting called (at least, not force). objects sit there , never collected (i can see weak references still having value). in 64-bit mode, weak references cleared expected, , finalizers called.
note: though code above on small scale, have noticed in 32-bit mode many more objects stuck in gc until more objects created later (even when "collect" , "waitforpendingfinalizers" called). never case in 64-bit mode. have 1 user wondering why many objects not getting collected, caused me investigate, found out seems work better in 64-bit mode 32. trying understand why.
edit: here better code show differences:
class program { class test { public static bool finalized = false; public int id; public test(int id) { id = id; } ~test() { // <= put breakpoint here finalized = true; console.writeline("test " + id + " finalized."); } } static list<weakreference> weakreferences = new list<weakreference>(); public static bool isnet45ornewer() { // class "reflectioncontext" exists .net 4.5 onwards. return type.gettype("system.reflection.reflectioncontext", false) != null; } static void main(string[] args) { console.writeline("is 4.5 or newer: " + isnet45ornewer()); console.writeline("intptr: " + intptr.size + environment.newline); console.writeline("creating objects ..."); (var = 0; < 10; ++i) weakreferences.add(new weakreference(new test(i))); console.writeline("triggering collect ..."); gc.collect(); console.writeline("triggering finalizers ..." + environment.newline); gc.waitforpendingfinalizers(); console.writeline(environment.newline + "checking objects still not finalized ..."); bool ok = true; (var = 0; < 10; ++i) if (weakreferences[i].isalive) { var test = (test)weakreferences[i].target; if (test != null) console.writeline("weak references still exist test " + test.id + "."); ok = false; } if (ok) console.writeline("all test objects collected , finalized."); console.writeline(environment.newline + "creating more objects ..."); (var = 0; < 10; ++i) weakreferences.add(new weakreference(new test(i))); console.writeline("triggering collect ..."); gc.collect(); console.writeline("triggering finalizers ..." + environment.newline); gc.waitforpendingfinalizers(); console.writeline(environment.newline + "checking objects still not finalized ..."); ok = true; (var = 0; < 10; ++i) if (weakreferences[i].isalive) { var test = (test)weakreferences[i].target; if (test != null) console.writeline("weak references still exist test " + test.id + "."); ok = false; } if (ok) console.writeline("all test objects collected , finalized."); console.writeline(environment.newline + "done."); console.readkey(); } }
it works in 64-bit, not in 32-bit. on system, "test #9" never gets collected (a weak reference remains), after creating more objects, , trying second time.
fyi: main reason asking question because have \gctest
option in console test garbage collection between v8.net , underlying v8 engine on native side. works in 64-bit, not 32.
no repro on vs2013 + .net 4.5 on x86 , x64:
class program { class test { public readonly int i; public test(int i) { = i; } ~test() { console.writeline("finalizer " + i); } } static void tester() { var t = new test(1); } public static bool isnet45ornewer() { // class "reflectioncontext" exists .net 4.5 onwards. return type.gettype("system.reflection.reflectioncontext", false) != null; } static void main(string[] args) { console.writeline("is 4.5 or newer: " + isnet45ornewer()); console.writeline("intptr: " + intptr.size); var t = new test(2); t = null; new test(3); tester(); console.writeline("pre gc"); gc.collect(); gc.waitforpendingfinalizers(); console.writeline("post gc"); console.readkey(); } }
note (as noticed @sriram sakthivel), there "ghost" copies of variable around, have lifespan extended until end of method (when compile code in debug mode or have debugger attached (f5 instead of ctrl+f5), lifespan of variables extended until end of method ease debugging)
for example object initialization (when new foo { = 5 }) creates hidden local variable.
Comments
Post a Comment