为了掌握弱引用(weak reference)的用法,考虑前面Get方法的修改版本:
Public static FancyObject Get(string name)
{
Lock (typeof(FancyObjects))
{
//用于弱引用的检查缓存
weakReference weak=(WeakReference)table[name];
//试图解除弱引用
FancyObject result=null;
If(weak!=null)
Result=(FancyObject)weak.Target;
//如果缓存中没有或者已经被垃圾回收了,就创建并加入缓存
If(result==null)
{
Result=new FancyObject(name);
//只缓存弱引用!
Table[name]=new WeakReference(result);
}
Return result;
}
}
注意,散列表持有的只是弱引用,这意味着缓存中的引用不能防止目标对象被垃圾叵收。还要注意的是,当你在这个缓存上执行查找时,你必须确保目标对象在它被加入缓存后没有被回收。可以通过检查Target属性是否为null做到这一点。
只有当特定资源不够用时,CLR才会执行垃圾回收器。当这种情形发生时,CLR接管CPU,通过一个根引用跟踪可到达的对象。在识别所有这些对象后,垃圾回收器将收集堆上的剩余内存,用于后续的内存分配。作为内存回收的一部分,垃圾回收器将在内存中重新定位存活的对象,以避免产生堆碎片,并且,通过将存活的对象保存在更少的虚拟内存页中来调节进程的工作集(下面这段话引自MSDN2003,能够帮助读者理解垃圾回收的过程“存回收中垃圾回收器检查托管堆,查找无法访问对象所占据的地址空间块。当发现无法访问的对象时.它就使用内存复制功能来压缩内存中可以访问的对象,释放分配给不可访问对象的地址空间块,在压缩了可访问对象的内存后,垃圾回收器就会做出必要的指针更正,以便应用程序的根指向新地址中的对象。‘它还将托管堆指针定位至最后一个可访问时象之后。”这样一来就压缩了内存,从而减少程序的工作集。——译者注)
CLR通过System.GC类以可编程的方式公开垃圾回收器。最有意思的方法是Collect,它指示CLR立刻执行垃圾回收。示例5.18展示了该方法的使用。注意,在这个示例中,当第一次调用System.GC.Collect时,你就可以回收r2引用的对象,尽管该引用仍在c#的词法作用域内,但CLR能侦查到该引用对象不再被需要。在第二次调用System.GC.Collect执行时,你就可以回收rl和r3所引用的对象,因为r1已经被显式地设置为null,面r3不再是一个存活的变量。你可以通过插入一个对System.GC.KeepAlive的调用,将一个对象引用保持为“存活”状态,以“欺骗”垃圾回收器。这个静态方法除了欺骗CLR,让它认为作为参数传递的引用是实际需要的,其他什么也不做。这样一来就使得引用的对象不被回收了。
示例5.18 存活和垃圾回收
Class UseEm{
Static Object r1; //r1是一个根!
Static void Main(){
R1=new Object();
Object r2=new Object();
Object r3=new Object();
System.GC.Collect(); //这里能够回收什么?
R1=null;
R3.ToString();
System.GC.Collect(); //这里能够回收什么?
}
}
Collect方法接收一个可选的参数,该参数可用于控制对未被引用对象的搜索范围,CLR使用一个被称为生成代(generation)的算法,如果一个对象被引用得越久,它被垃圾回收的可能性就越小。Collect方法允许你指定一个对象有多“老”。不过,频繁地调用GC.Collect会对性能产生负面的影响。魰@b錘 g頃Th~{僛/f(u /