Weak Reference

本文简述dotNet中Weak Reference(弱引用)的功能,并举例在具体应用场景中的效果。

 

首先,让我们回忆一下dotNet CLR的对象生命周期管理。为了解决对象引用计数器以及编码不慎可能导致的内存泄漏,dotNet CLR引入了Garbage Collection(GC)机制。GC会不时的扫描程序,将程序中不再使用的对象进行回收。

那么,怎样的对象才是不再被使用的呢?通常的,我们可以简单认为,在未关联至任何变量(包括对象属性、集合内成员等)的情况下的对象,也就是说,无法被安全的访问到的对象,会被认为是不再被使用的对象。那么,有没有例外呢?

这个例外,就是dotNet中的Weak Reference。它的直接功能,就是封装对一个对象的引用,但不会被GC认做有效的关联。换言之,GC在判断对象是否不再被使用时,不会考虑Weak Reference的引用。

Weak Reference类位于System命名空间下。我们可以通过其构造器直接构造一个对象。System.WeakReference有两个构造器,通常我们使用的第一个,要求传送一个object作为其引用的实际对象(Target属性);第二个构造器需要传送一个bool类型变量,用以定义是否进行长程跟踪,本功能不在本文中进行描述。

当我们构造好一个System.WeakReference后,我们可以通过访问其Target属性,设置或读取其引用的实际变量。由于GC不会考虑Weak Reference中对象的引用,如果Target属性的对象仅被引用于Weak Reference对象时,这个对象则随时可能被GC回收。

我们可以通过判断Weak Reference对象的IsAlive属性,来确定Target属性指向的对象是否已经被回收。当IsAlive为false时,Target属性也将被自动赋值为null。特别的,由于Target属性也可以被显式的赋值为null,我们应该使用IsAlive来进行判断,而不要使用Target属性是否为null来推断。

 

那么,Weak Reference有什么实际用途呢?

有时候,我们需要访问一个对象,却又不想管理其生命周期。例如,我们可能在要某段代码中,将某个窗体对象赋值至一个对象属性中,但我们又不希望由于这个对象未被回收,影响到原窗体的生命周期。如果我们使用Weak Reference对象,代替原属性值,即可避免这种情况的出现。

另外,有些数据,我们并不会经常的访问,但所有的访问又相对密集。这时候我们也可以使用Weak Reference来对数据进行封装。每次访问时,通过判断IsAlive来确定,是否需要构造其Target。由于GC通常不会在系统繁忙时激活,所以这种类似Cache的应用,通常只会在资源不足或系统空闲时才会被回收,而且这种回收是由dotNet CLR负责实现,无需用户编码干预。

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.