1

This program prints "True" to console.

Allocate an object, make WeakReference of that, go to out of block scope, and check WeakReference.IsAlive.

public static void Main (string[] args)
{
    Test ();
}

static void Test ()
{
    WeakReference wref = null;

    { // block scope
        var obj = new object ();
        wref = new WeakReference (obj);
    }

    // obj is out of scope
    // Console.WriteLine (obj);

    GC.Collect ();

    Console.WriteLine (wref.IsAlive); // => True
}

Why obj is not collected, though obj is out of scope?

The program is compiled by Mono 3.12.0.

EDIT:

Sorry, inappropriate example.

The following program also print True. Block scope seems be not related. This is tried not with Debug mode.

    public static void Main (string[] args)
    {
        Test ();
    }

    static void Test ()
    {
        WeakReference wref = null;

        var obj = new object ();
        wref = new WeakReference (obj);
        obj = null;

        GC.Collect ();

        Console.WriteLine (wref.IsAlive); // => True
    }

$ mcs -debug- Program.cs
$ mono Program.exe

homu
  • 119
  • 5

3 Answers3

2

Because you're running in the debugger, I'd guess.

Try running the release version, and run it manually, outside of the debugger.

Luaan
  • 62,244
  • 7
  • 97
  • 116
  • Note that in regular .Net the difference is whether executable compile for debug and release configuration (/debug+ or /debug- compiler flag). I don't think that when debugger is attached then release IL changes lifetime spans for local variables, but not sure. – Alexei Levenkov Jul 17 '15 at 05:12
  • @AlexeiLevenkov When the debugger is attached, the JIT compiler compiles things differently. In fact, C# doesn't care about block scope at all - in scope or not, without the debugger attached, any local that's not going to be used in the future is immediately "free for collection". With a debugger attached, it lives to the end of the method. – Luaan Jul 17 '15 at 05:17
  • its true.also in debug if you manually set `obj = null;` it will print false – M.kazem Akhgary Jul 17 '15 at 05:21
  • @Luaan you are right... Indeed JIT when "suppress optimizations on load" is checked will behave the same for newly JIT-ed methods even for release build. Without debugger I believe debug and release builds will still behave differently (http://blogs.msdn.com/b/jaybaz_ms/archive/2004/06/28/168314.aspx) - at least what my test of code provided by OP shows... – Alexei Levenkov Jul 17 '15 at 05:32
1

You expect the GC to be 100% deterministic, when it's not.

A few things that might have happened:

  • The JIT optimized the null assignment away.
  • A pointer to the instance can be left over in a temporary stack location, or in a register (you called a function, passing the variable, that will put the variable in a register on certain architectures).
Rolf Bjarne Kvinge
  • 19,253
  • 2
  • 42
  • 86
0

After GC.Collect, add :

GC.WaitForPendingFinalizers(); 

By calling this procedure, all finalizable objects can perform any necessary cleanup before continuing your program. It ensures your code does not invoke methods on an object currently being destroyed.

Graffito
  • 1,658
  • 1
  • 11
  • 10