一、弱引用:
我们设计全局缓存时,使用静态或全局字段来引用某个对象,做到一次创建多次使用。比如:
class Program
{
private static DataCache _cache;
public static DataCache Cache
{
get
{
if(_cache == null)
_cache = new DataCache();
return _cache;
}
}
static void Main(string[] args)
{
byte [] ss = new byte[]{1,2,3};
GC.Collect();
Console.WriteLine("GC执行完毕");
Console.Read();
}
}
class DataCache
{
private IList<string> datas;
}
但这样存在弊端:
- DataCache没频繁使用时,浪费内存空间。
- 由于GC只能回收不可达对象,所以没有办法回收这些资源。
WeakReference出场:即在引用对象的同时仍然允许对该对象进行垃圾回收。
所以我们可以这样设计缓存:
class Program
{
static WeakReference _cache = new WeakReference(null);
public static DataCache Cache
{
get
{
DataCache cache = _cache.Target as DataCache;
if(cache == null)
{
cache = new DataCache();
_cache.Target = cache;
}
return cache;
}
}
static void Main(string[] args)
{
byte [] ss = new byte[]{1,2,3};
Cache.Test();
Cache.Test();
GC.Collect();
Console.WriteLine("GC执行完毕");
Cache.Test();
Console.Read();
}
}
class DataCache
{
private IList<string> datas;
~DataCache()
{
Console.WriteLine("Destory...");
}
public void Test()
{
Console.WriteLine("Test");
}
}
二、弱委托
弱委托解决当委托对象的生命周期足够的长时,导致委托内部持有的强对象不能回收,
比如:
class Program
{
static void Main(string[] args)
{
Action<string> sAction = new Action<string>(new ClassTest().Print);
sAction("abc");
GC.Collect();
sAction("abc");
}
}
internal class ClassTest
{
public void Print(string s)
{
Console.WriteLine(s);
}
}
输出结果为:abc abc
为了解决当垃圾回收进行时,委托的对象任然存在,就用到了WeakReference
class Program
{
static void Main(string[] args)
{
Action<string> sAction = new Action<string>(new ClassTest().Print);
WeakReference weakReference = new WeakReference(new ClassTest());
sAction = (s) =>
{
object o = weakReference.Target;
if (o != null)
{
((ClassTest)o).Print(s);
}
};
sAction("def");
GC.Collect();
sAction("def");
}
}
internal class ClassTest
{
public void Print(string s)
{
Console.WriteLine(s);
}
}
输出结果当然只有一个def了。
CLR var C#中的弱委托:
public abstract class WeakDelegate<TDelegate> where TDelegate : class /* MulticastDelegate */ {
// This lightweight private struct puts a compile-time type-safety wrapper around the non-generic WeakReference class
private struct WeakReference<T> : IDisposable where T : class {
private WeakReference m_weakReference;
public WeakReference(T target) { m_weakReference = new WeakReference(target); }
public T Target { get { return (T)m_weakReference.Target; } }
public void Dispose() { m_weakReference = null; }
}
private WeakReference<TDelegate> m_weakDelegate;
private Action<TDelegate> m_removeDelegateCode;
public WeakDelegate(TDelegate @delegate) {
var md = (MulticastDelegate)(Object)@delegate;
if (md.Target == null)
throw new ArgumentException("There is no reason to make a WeakDelegate to a static method.");
// Save a WeakReference to the delegate
m_weakDelegate = new WeakReference<TDelegate>(@delegate);
}
public Action<TDelegate> RemoveDelegateCode {
set {
// Save the delegate that refers to code that knows how to remove the
// WeakDelegate object when the non-weak delegate object is GC’d
m_removeDelegateCode = value;
}
}
protected TDelegate GetRealDelegate() {
// If the real delegate hasn't been GC'd yet, just return it
TDelegate realDelegate = m_weakDelegate.Target;
if (realDelegate != null) return realDelegate;
// The real delegate was GC'd, we don't need our WeakReference to it anymore (it can be GC'd)
m_weakDelegate.Dispose();
// Remove the delegate from the chain (if the user told us how)
if (m_removeDelegateCode != null) {
m_removeDelegateCode(GetDelegate());
m_removeDelegateCode = null; // Let the remove handler delegate be GC'd
}
return null; // The real delegate was GC'd and can't be called
}
// All derived classes must return a delegate to a private method matching the TDelegate type
public abstract TDelegate GetDelegate();
// Implicit conversion operator to convert a WeakDelegate object to an actual delegate
public static implicit operator TDelegate(WeakDelegate<TDelegate> @delegate) {
return @delegate.GetDelegate();
}
}
// This class provides support for the non-generic EventHandler delegate
public sealed class WeakEventHandler : WeakDelegate<EventHandler> {
public WeakEventHandler(EventHandler @delegate) : base(@delegate) { }
/// <summary>Returns a reference to the non-generic EventHandler delegate</summary>
public override EventHandler GetDelegate() { return Callback; }
// This private method must match the desired delegate’s signature
private void Callback(Object sender, EventArgs e) {
// If the target hasn't been GC'd invoke it
var eh = base.GetRealDelegate();
if (eh != null) eh(sender, e);
}
}
// This WeakDelegate partial class provides support for the generic EventHandler<TEventArgs> delegate
public sealed class WeakEventHandler<TEventArgs> : WeakDelegate<EventHandler<TEventArgs>> where TEventArgs : EventArgs {
public WeakEventHandler(EventHandler<TEventArgs> @delegate) : base(@delegate) { }
/// <summary>Returns a reference to the generic EventHandler<typeparam name="TEventArgs"/> delegate</summary>
public override EventHandler<TEventArgs> GetDelegate() { return Callback; }
private void Callback(Object sender, TEventArgs e) {
// If the target hasn't been GC'd invoke it
var eh = base.GetRealDelegate();
if (eh != null) eh(sender, e);
}
}