Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collect objects still in scope - GC.Collect

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?

like image 859
Daniel Bişar Avatar asked Jun 21 '11 12:06

Daniel Bişar


People also ask

How does the garbage collector determines which objects to remove from memory?

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.

When garbage collector runs c#?

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.

What does the garbage collector GC in. net do?

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.


1 Answers

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.

like image 121
MerickOWA Avatar answered Sep 30 '22 09:09

MerickOWA