I recently came across this SO article and tweaked it for my scenario which follows:
using System;
using System.Collections.Generic;
namespace ConsoleApplication18
{
class Program
{
static void Main(string[] args)
{
Manager mgr = new Manager();
var obj = new byte[1024];
var refContainer = new RefContainer();
refContainer.Target = obj;
obj = null;
mgr["abc"] = refContainer.Target;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
Console.WriteLine(mgr["abc"] != null); // true (still ref'd by "obj")
refContainer = null;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
Console.WriteLine(mgr["abc"] != null); // false (no remaining refs)
}
}
class RefContainer
{
public object Target { get; set; }
}
class Manager
{
Dictionary<string, WeakReference> refs =
new Dictionary<string, WeakReference>();
public object this[string key]
{
get
{
WeakReference wr;
if (refs.TryGetValue(key, out wr))
{
if (wr.IsAlive)
return wr.Target;
refs.Remove(key);
}
return null;
}
set
{
refs[key] = new WeakReference(value);
}
}
}
}
Running this program gives the following expected result:
True
False
Press any key to continue . . .
However change this:
var refContainer = new RefContainer();
refContainer.Target = obj;
To this (using Object Initializer syntax):
var refContainer = new RefContainer() { Target = obj };
Gives the following output:
True
True
Press any key to continue . . .
What's going on here? Why would lifetime of the reference be different just because of using Object Initializer?
In object initializer, you can initialize the value to the fields or properties of a class at the time of creating an object without calling a constructor. In this syntax, you can create an object and then this syntax initializes the freshly created object with its properties, to the variable in the assignment.
Initializing an ObjectThis class contains a single constructor. You can recognize a constructor because its declaration uses the same name as the class and it has no return type. The constructor in the Point class takes two integer arguments, as declared by the code (int a, int b).
An object initializer is an expression that describes the initialization of an Object . Objects consist of properties, which are used to describe an object. The values of object properties can either contain primitive data types or other objects.
Initializing an object means storing data into the object. Let's see a simple example where we are going to initialize the object through a reference variable. We can also create multiple objects and store information in it through reference variable.
Why would lifetime of the reference be different just because of using Object Initializer?
I can't actually reproduce your problem anyway, but I suspect it's because this:
var refContainer = new RefContainer() { Target = obj };
is equivalent to:
var tmp = new RefContainer();
tmp.Target = obj;
var refContainer = tmp;
... so you end up with an extra reference to the object on the stack. Now when running not under the debugger, I'd expect the GC to notice that that stack location is never read again, and allow the object to be garbage collected - but as you're running under the debugger, the GC is more conservative, and I suspect it treats all stack variables as GC roots.
That's just a guess though - without being able to reproduce it anyway, it's hard to say for sure.
EDIT: Your assignments of obj = null;
and refContainer = null;
are pointless under non-debug mode; because the variables aren't read after that point anyway, the GC ignores them as GC roots.
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