.net框架读书笔记---CLR内存管理\垃圾收集(四) - 恒星的恒心- 博客园

弱引用

  当一个根指向一个对象时,该对象不可能被垃圾收集器收集,在这种情况下,通常说存在一个该对象的强引用(strong reference)。垃圾收集器还支持弱引用(weak reference)的概念。弱引用允许垃圾收集器收集对象,同时也允许应用程序访问该对象,结果取决于时间。

  如果对象的弱引用存在,那么在垃圾收集执行后,该对象的内存将被执行,另一方面,要访问一个弱引用对象,应用程序必须获取该对象的一个强引用。如果应用程序在对象被执行之前得到了它的强引用,那么垃圾收集器将不再对该对象执行垃圾收集,因为这时存在一个该对象的强引用。

  下面代码展示了弱引用的使用

代码
class Program
{
static void Main(string[] args)
{
SomeWeakReferenceMethod();
SomeStrongtReferenceMethod();
}

static void SomeWeakReferenceMethod()
{
//创建一个强引用对象
SomeClass o = new SomeClass();

WeakReference wr
= new WeakReference(o);

o
= null;//移除对象的强引用

o
= wr.Target as SomeClass;

if (o == null)
{
//出现过垃圾回收,对象的内存已经被回收
Console.WriteLine("已经被回收");
}
else
{
//未出现垃圾回收
Console.WriteLine("没有被回收"+o.X.ToString());
}

}
static void SomeStrongtReferenceMethod()
{
//创建一个强引用对象
SomeClass o = new SomeClass();
o
= null;//移除对象的强引用
try
{
Console.WriteLine(o.X);
}
catch
{
Console.WriteLine(
"error");
}
}


}

public class SomeClass
{
private int x;

public int X
{
get
{
return this.x;
}
}

public SomeClass()
{
x
= 5;
}
}

个人感觉弱引用机制有点像缓存,将一些操作起来比较费时(比如便利系统的硬盘)的东西{dy}次获取之后暂时放入缓存中,并且将其引用置为null来减少应用程序的压力,但是放置在缓存中可以再次使用(减少读取时的压力),至于是否能够再次使用成功要看垃圾收集器。如果执行过垃圾收集,弱引用的对象将会被回收掉当然就无法再次使用了。

  System.WeakReference有两个公用构造器:

  • public WeakReference(object target);
  •  public WeakReference(object target, bool trackResurrection);

  target表示要追踪的对象(上例中为SomeClass), trackResurrection表示是否要追踪对象的复苏,换句话说就是对象在执行Finalize方法后,是否还要追踪该对象(对象执行Finlize后对象复苏了) 。

  将不追踪对象复苏的WeakReference称为短弱引用(short weak reference),而将追踪对象复苏的称为长弱引用(long weak reference)。如果一个对象没有Finalize方法,长短弱引用是一样的,{zh0}不要使用长弱引用,因为长弱引用在一个对象被执行终止后允许该对象复苏,将会导致对象的状态不可预知。

  一旦创建了对象的弱引用,通常将该对象的强引用设置为null,为了再次使用该对象,需要将弱引用转换为一个强引用,通过WeakReference的Target属性来完成的。如果target为null,那么对象已经被执行了垃圾收集,否则将会得到该对象的强引用。这时对象将不会被垃圾收集器收集了。

弱引用的内部机理

  需要再次探究托管堆。托管堆中包含了两个内部数据结构来管理弱引用。即短弱引用表和长弱引用表。这两个表包含着一些指针,他们引用着托管堆对象。

  当创建一个WeakReference对象时,它会在两个弱引用表中选择一个(长短弱引用相应对应),并在其中寻找一个空白插槽。该插槽的值将被设为我们希望追踪对象的地址---也就是new WeakReference构造的那个对象的地址,弱引用表将不会认为是应用程序的根,否则垃圾收集器将不能收集它们中的指针引用的对象。

  垃圾收集器运行时发生的一系列事情:

  • 垃圾收集器构造一个可达对象的图();
  • 垃圾收集器扫描短弱引用表,如果表中的对象不是前面可达对象图的一部分(对象已经不是根,在上面的例子中o已经被置为null了),那么表示该对象是一个不可达的对象,将短弱引用表中对应插槽的值将被设置为null(Target为null了);
  • 垃圾收集器扫描终止化链表()。如果该链表中指针引用的对象不是可达对象图的一部分,那么该对象将是不可达对象,它将被从终止化链表转移到终止化可达队列上。这时对象由成为可达对象图的一部分了。
  • 垃圾收集器扫描长弱引用表,如果表中的对象不是前面可达对象图的一部分(该图现在已经包括终止化可达队列中引用的对象了),那么表示该对象是一个不可达的对象,将长弱引用表中对应插槽的值将被设置为null(Target为null了);
  • 垃圾收集器压缩内存,填充不可达对象空出的位置。

  继续分析代码

 

代码
if (o == null)
{
//出现过垃圾回收,对象的内存已经被回收
Console.WriteLine("已经被回收");
}
else
{
//未出现垃圾回收
Console.WriteLine("没有被回收"+o.X.ToString());
}

 

 

因为在此之前o已经被置为null了,所以它已经是一个不可达对象,如果执行垃圾收集器,o自然不在可达对象图中,那么垃圾收集器将会将短弱引用表中插槽对应的值设为null,这样Target将返回null,上面代码自然会执行if里面的代码。如果垃圾收集器还没有执行,虽然o已经为null,但是短弱引用插槽依然保存着对象的引用,那么Target将会返回对象的引用,使对象继续可达,可以使用,当然上面代码就会执行else里面的代码。

  短弱引用并不追踪对象的复苏。只要垃圾收集器判断对象成为不可达的对象,它就会把短弱引用表中对应的指针设置为null。如果对象重写了Finalize方法,那么这时该方法还没有被调用,所以对象仍然存在。此时target仍然返回null,虽然这时对象已经进入终止化可达队列,对象仍然存在。

  

  

posted on 2010-05-15 19:18 阅读(11)   所属分类:

昵称:

主页:

邮箱:(仅博主可见)

评论内容:

    

[使用Ctrl+Enter键快速提交评论]

郑重声明:资讯 【.net框架读书笔记---CLR内存管理\垃圾收集(四) - 恒星的恒心- 博客园】由 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
—— 相关资讯 ——