I have read this article: http://blogs.msdn.com/b/oldnewthing/archive/2010/08/10/10048149.aspx and honestly I don't understand every detail. As far as i understand in the code below c should be collected even if i don't set c to null. Another thing is that allocations happening during a foreach seem to be not freed as long as we in the scope of the same function. (See example below)
class Program
{
public class SomeClass
{
public byte[] X;
public SomeClass()
{
X = new byte[1024 * 1024 * 100];
X[155] = 10;
}
}
static void Main()
{
Console.WriteLine("Memory: " + GC.GetTotalMemory(false));
SomeClass c;
c = new SomeClass();
Console.WriteLine("Memory: " + GC.GetTotalMemory(false));
GC.Collect();
Console.WriteLine("Memory: " + GC.GetTotalMemory(true));
Console.ReadKey();
/*
* Output:
*
* Memory: 186836
* Memory: 105044468
* Memory: 104963676
*
*/
}
}
EDIT The solution for the first example: The Debug-Mode (not running in debugger but even the compilation-mode). If I use Release it'll work as expected: c is collected even without setting to null. For Second example the same applies.
Second example
static void Main(string[] args)
{
Console.WriteLine("Startup Memory: " + GC.GetTotalMemory(false));
var obj = BOObject.Get();
Console.WriteLine("Fetched Object: " + GC.GetTotalMemory(false));
GC.Collect();
Console.WriteLine("Fetched Object (Collected): " + GC.GetTotalMemory(false));
foreach (var node in obj.Traverse())
{
string name = node.Name;
}
Console.WriteLine("Traversed: " + GC.GetTotalMemory(false));
GC.Collect();
Console.WriteLine("Traversed (collected): " + GC.GetTotalMemory(false));
obj = null;
GC.Collect();
Console.WriteLine("collected: " + GC.GetTotalMemory(true));
Console.Read();
}
Output:
Startup Memory: 193060 Fetched: 8972464 Fetched (Collected): 5594308 Traversed: 272553096 Traversed (collected): 269564660 collected: 269564048
If i put the foreach loop in another function and call this function the memory used after .Collect is call is about 5800000. So why the garbage is not collected when i have the foreach loop in the same function?
When the garbage collector performs a collection, it releases the memory for objects that are no longer being used by the application. It determines which objects are no longer being used by examining the application's roots.
Garbage collection occurs when one of the following conditions is true: The system has low physical memory. The memory that is used by allocated objects on the managed heap surpasses an acceptable threshold. This threshold is continuously adjusted as the process runs.
NET's garbage collector manages the allocation and release of memory for your application. Each time you create a new object, the common language runtime allocates memory for the object from the managed heap.
Mentioned in the comments to Raymond's article and in Yun Jin's MSDN article here that
In fact, for debuggable code, JIT extends lifetime for every variable to end of the function.
Therefore your collection won't be collected in Debug mode as you discovered and why it will be collected in Release mode.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With