System.WeakReference的实际使用
我了解System.WeakReference的功能,但是我似乎无法理解的是一个可能有用的实际示例。在我看来,这堂课本身就是一种技巧。在我看来,还有其他更好的解决问题的方法,其中在我所看到的示例中使用了WeakReference。我们真正需要在哪里使用WeakReference的规范示例是什么?我们不是在尝试远离此类行为和此类的使用吗?
解决方案
回答
我使用它来实现一个缓存,在该缓存中,未使用的条目将自动被垃圾收集:
class Cache<TKey,TValue> : IEnumerable<KeyValuePair<TKey,TValue>> { Dictionary<TKey,WeakReference> dict = new Dictionary<TKey,WeakReference>(); public TValue this[TKey key] { get {lock(dict){ return getInternal(key);}} set {lock(dict){ setInteral(key,value);}} } void setInteral(TKey key, TValue val) { if (dict.ContainsKey(key)) dict[key].Target = val; else dict.Add(key,new WeakReference(val)); } public void Clear() { dict.Clear(); } /// <summary>Removes any dead weak references</summary> /// <returns>The number of cleaned-up weak references</returns> public int CleanUp() { List<TKey> toRemove = new List<TKey>(dict.Count); foreach(KeyValuePair<TKey,WeakReference> kv in dict) { if (!kv.Value.IsAlive) toRemove.Add(kv.Key); } foreach (TKey k in toRemove) dict.Remove(k); return toRemove.Count; } public bool Contains(string key) { lock (dict) { return containsInternal(key); } } bool containsInternal(TKey key) { return (dict.ContainsKey(key) && dict[key].IsAlive); } public bool Exists(Predicate<TValue> match) { if (match==null) throw new ArgumentNullException("match"); lock (dict) { foreach (WeakReference weakref in dict.Values) { if ( weakref.IsAlive && match((TValue) weakref.Target)) return true; } } return false; } /* ... */ }
回答
一个有用的例子是运行DB4O面向对象数据库的人。在那里,WeakReferences用作一种轻型缓存:它仅在应用程序运行时将对象保留在内存中,从而使我们可以将真正的缓存放在最上面。
另一个用途是在弱事件处理程序的实现中。当前,.NET应用程序中内存泄漏的一大原因就是忘记删除事件处理程序。例如。
public MyForm() { MyApplication.Foo += someHandler; }
看到问题了吗?在上面的代码段中,只要MyApplication在内存中处于活动状态,MyForm就会一直在内存中保持活动状态。创建10个MyForms,将其全部关闭,10个MyForms仍将保留在内存中,并由事件处理程序保持活动状态。
输入WeakReference。我们可以使用WeakReferences构建弱事件处理程序,以便someHandler是MyApplication.Foo的弱事件处理程序,从而解决内存泄漏!
这不只是理论。 DidItWith.NET博客的Dustin Campbell发布了使用System.WeakReference实现的弱事件处理程序。
回答
我在mixin中使用弱引用进行状态维护。请记住,mixin是静态的,因此当我们使用静态对象将状态添加到非静态对象时,我们永远不会知道需要多长时间。因此,我保留了Dictionary <WeakReference,myvalue>而不是保留Dictionary <myobject,myvalue>,以防止mixin拖东西太久。
唯一的问题是,每次进行访问时,我还会检查无效引用并将其删除。当然,并不是说他们伤害了任何人,除非有成千上万的人。