让我先把它放回去:
当您要在对象上保留选项卡,但又不想让观察结果阻止该对象被收集时,WeakReference很有用。
因此,让我们从头开始:
-对任何无意的冒犯表示歉意,但是我暂时要回到“迪克和简”的级别,因为永远无法告诉观众。
因此,当您有一个对象时X
-让我们将其指定为-的实例class Foo
-它就不能靠它自己生存(大多数情况下是这样);就像“没有人是一个岛”一样,只有几种方法可以将对象提升为Islandhood -尽管在CLR语言中它被称为GC根。成为GC根,或已建立到GC根的连接/引用链,基本上决定了是否Foo x = new Foo()
收集垃圾。
如果您无法通过堆或堆栈遍历返回某些GC根目录,那么您实际上是孤立的,可能会在下一个周期被标记/收集。
在这一点上,让我们看一些可怕的例子:
首先,我们的Foo
:
public class Foo
{
private static volatile int _ref = 0;
public event EventHandler FooEvent;
public Foo()
{
_ref++;
Console.WriteLine("I am #{0}", _ref);
}
~Foo()
{
Console.WriteLine("#{0} dying!", _ref--);
}
}
相当简单-它不是线程安全的,所以不要尝试这样做,而是在活动实例和减量完成时保留它们的“引用计数”。
现在让我们来看一个FooConsumer
:
public class NastySingleton
{
// Static member status is one way to "get promoted" to a GC root...
private static NastySingleton _instance = new NastySingleton();
public static NastySingleton Instance { get { return _instance;} }
// testing out "Hard references"
private Dictionary<Foo, int> _counter = new Dictionary<Foo,int>();
// testing out "Weak references"
private Dictionary<WeakReference, int> _weakCounter = new Dictionary<WeakReference,int>();
// Creates a strong link to Foo instance
public void ListenToThisFoo(Foo foo)
{
_counter[foo] = 0;
foo.FooEvent += (o, e) => _counter[foo]++;
}
// Creates a weak link to Foo instance
public void ListenToThisFooWeakly(Foo foo)
{
WeakReference fooRef = new WeakReference(foo);
_weakCounter[fooRef] = 0;
foo.FooEvent += (o, e) => _weakCounter[fooRef]++;
}
private void HandleEvent(object sender, EventArgs args, Foo originalfoo)
{
Console.WriteLine("Derp");
}
}
因此,我们有一个对象已经是它自己的GC根了(具体来说,它将通过一条直接链接到运行此应用程序的应用程序域的根,但这是另一个主题),它具有两种方法锁住Foo
实例的方法-让我们对其进行测试:
// Our foo
var f = new Foo();
// Create a "hard reference"
NastySingleton.Instance.ListenToThisFoo(f);
// Ok, we're done with this foo
f = null;
// Force collection of all orphaned objects
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
现在,从上面开始,您是否希望曾经被引用的对象f
是“可收集的”?
不,因为现在有另一个对象拥有对该对象的引用- Dictionary
在该Singleton
静态实例中。
好吧,让我们尝试一下弱方法:
f = new Foo();
NastySingleton.Instance.ListenToThisFooWeakly(f);
// Ok, we're done with this foo
f = null;
// Force collection of all orphaned objects
// This should collect # 2 - you'll see a "#2 dying"
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
现在,当我们重用Foo
-the-was-once-的f
引用时,不再有对该对象的“硬”引用,因此它是可收集的- WeakReference
弱侦听器创建的对象不会阻止这种情况。
良好的用例:
事件处理程序(尽管请先阅读以下内容:C#中的弱事件)
您可能会导致“递归引用”(即,对象A引用对象B,后者引用对象A,也称为“内存泄漏”),这种情况(编辑:derp,当然这不是不是真的)
您想将某事物“广播”到一组对象中,但是您不想成为使它们存活的事物。一个List<WeakReference>
能够容易地保持,甚至修剪通过去除其中ref.Target == null