关于.NE弱引用的一些个人理解

首先为什么要有弱引用:

这个问题比较有意思,大家都知道一个对象有引用就不可能被GC,没有引用就会被GC,而有一种对象有引用依然会被GC掉,哈哈,是不是有点费解。

其实有这么一种应用:比如我想为了程序需要建立一个硬盘的所有文件目录列表,出于性能考虑这个列表被放置在内存中,而程序去作其他事情的时候,把这个目录放到若引用上,当程序内存比较吃力时,GC来临回收该目录,当程序内存够用时,不进行GC则这个目录依然在内存中,这样就方便了程序对内存的控制,内存紧我就干掉你,内存不紧就留这你,像个战士,战事紧你就牺牲,战事不紧你就活着。

用法:

Void Method() {
   Object o = new Object();    // 创建一个对象的强引用
   // Create a strong reference to a short WeakReference object.
   // The WeakReference object tracks the Object.
   WeakReference wr = new WeakReference(o);
   o = null;    // Remove the strong reference to the object
   o = wr.Target;
   if (o == null) {
      // A GC occurred and Object was reclaimed.
   } else {
      // a GC did not occur and we can successfully access the Object 
      // using o
   }
}
 

弱引用的内部原理

在上面的讨论中,很明显弱应用跟其它类型表现得不太一样。通常,如果你的程序根存在一个对该对象的引用,该对象又引用了另一个
对象,那么两个对象就是可访问的,且GC不可以重新分配这两个对象的内存。但是,如果你的程序根集存在一个弱引用对象,那么该
弱引用指向的对象不被认为是可达的,可能被回收。

为了更好的理解弱引用是如何工作的,我们在来看看托管对的内部。托管堆包含了两个内部数据结构母的是用于管理弱引用对象:
短弱引用表和长弱引用表。这两个表包含了指向托管对对象的指针。

初始化时候,两个表都是空的。当你创建一个弱应用对象,对象不会从托管对分配资源,而是从弱引用表中分配一个空的槽,
短弱引用类型使用短弱引用类型表,而长弱引用类型则使用长弱引用类型表。

一旦发现一个空槽,该槽的则就会被设置成为你想追踪对象的地址--也就是从WeakReference构造函数传递进去的对象指针。
实例化操作返回的就是该槽的地址。显然,两个弱引用表并不是程序根集合的一部分或者GC无法重新分配表中的对象指针。

现在,我们来看看GC运行时会发生什么情况:

1. GC建立一个可到达对象的图,文章第一部分 已经讨论过GC是如何实现。

2. GC搜索短弱引用表,如果表中指针指向的对象不是对象图的一部分,那么指针指向的是一个不可访问的对象,而该槽也会被
设置为null。

3. GC搜索finalization队列,如果队列中的指针指向的对象不是对象图的内容,那么指针表示的是一个不可访问对象,该指针
从finalization队列移动到freachable队列。在这点上,对象被添加到对象图中因为对象被认为是可访问的。

4. GC遍历长引用类型表,如果弱引用对象的指针不是图中的一部分(而在freachable队列包含了该对象的指针),那么指针
表示的是一个不可达的对象,同时该槽被设置为null

5. GC压缩内存,压缩那些unreachable对象留下来的空间。

一旦你了解了GC的运行逻辑,那么理解弱引用是如何工作就很容易了。访问弱引用的Target属性时,会使得系统反正的弱应用表中
的槽。如果该槽为null,那么对象就已经给回收了。

短弱引用是不会追踪重生的。这意味着,GC一旦认为对象是不可达的时候,则将短弱引用表中的指针设置成为null。如果对象具有
Finalize方法,这个方法还没被调用时,则这个对象还存在。如果程序访问弱引用类型的Target属性,则返回null,即使对象还存在。

一个长弱引用会追踪重生,这意味着当对象的存储空间被回收时,那么长弱引用表的指针则会设置成null。如果对象使用了Finalize
方法,那么Finalize会被调用,对象不再重生。

引用:http://www.cnblogs.com/coolkiss/archive/2010/08/31/1813665.html

posted @ 2012-12-06 15:33  剑桥  阅读(502)  评论(0编辑  收藏  举报