我明白什么 系统.弱引用 确实如此,但我似乎无法理解它可能有用的实际例子。在我看来,这个课程本身就是一个黑客。在我看来,还有其他更好的方法来解决我见过的示例中使用 Wea​​kReference 的问题。真正需要使用 Wea​​kReference 的典型示例是什么?我们不是想得到 更远 远离这种类型的行为和使用这个类?

有帮助吗?

解决方案

一个有用的例子是运行 DB4O 面向对象数据库的人。在那里,WeakReferences 被用作一种轻量级缓存:它只会将您的对象保留在内存中,只要您的应用程序保留,允许您在顶部放置一个真正的缓存。

另一个用途是弱事件处理程序的实现。目前,.NET 应用程序中内存泄漏的一大原因是忘记删除事件处理程序。例如。

public MyForm()
{
    MyApplication.Foo += someHandler;
}

看到问题了吗?在上面的代码片段中,只要 MyApplication 在内存中存活,MyForm 就会永远在内存中保持存活状态。创建 10 个 MyForms,将它们全部关闭,您的 10 个 MyForms 仍将在内存中,由事件处理程序保持活动状态。

输入弱引用。您可以使用 Wea​​kReferences 构建弱事件处理程序,以便 someHandler 成为 MyApplication.Foo 的弱事件处理程序,从而修复内存泄漏!

这不仅仅是理论。DidItWith.NET 博客的达斯汀·坎贝尔 (Dustin Campbell) 发布了 弱事件处理程序的实现 使用 System.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;
     }

    /* ... */
   }

我在 mixin 中使用弱引用来保持状态。请记住,mixin 是静态的,因此当您使用静态对象将状态附加到非静态对象时,您永远不知道需要多长时间。所以不要保留 Dictionary<myobject, myvalue> 我保留一个 Dictionary<WeakReference,myvalue> 以防止 mixin 拖拽东西太久。

唯一的问题是,每次进行访问时,我还会检查死引用并删除它们。当然,他们并不是伤害任何人,除非有数千人。

您使用的原因有两个 WeakReference.

  1. 而不是声明为静态的全局对象: :全局对象被声明为静态字段,并且静态字段不能被 GC(垃圾收集),直到 AppDomain 已进行 GC 处理。因此,您可能会面临内存不足异常的风险。相反,我们可以将全局对象包装在 WeakReference. 。尽管 WeakReference 本身被声明为静态的,当内存不足时,它指向的对象将被GC'ed。

    基本上,使用 wrStaticObject 代替 staticObject.

    class ThingsWrapper {
        //private static object staticObject = new object();
        private static WeakReference wrStaticObject 
            = new WeakReference(new object());
    }
    

    简单的应用程序,证明静态对象在 AppDomain 时被垃圾收集。

    class StaticGarbageTest
    {
        public static void Main1()
        {
            var s = new ThingsWrapper();
            s = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }
    class ThingsWrapper
    {
        private static Thing staticThing = new Thing("staticThing");
        private Thing privateThing = new Thing("privateThing");
        ~ThingsWrapper()
        { Console.WriteLine("~ThingsWrapper"); }
    }
    class Thing
    {
        protected string name;
        public Thing(string name) {
            this.name = name;
            Console.WriteLine("Thing() " + name);
        }
        public override string ToString() { return name; }
        ~Thing() { Console.WriteLine("~Thing() " + name); }
    }
    

    请注意下面的输出 staticThing 即使在之后也会在最后进行 GC ThingsWrapper 是 - 即GC 的时间 AppDomain 已进行 GC 处理。

    Thing() staticThing
    Thing() privateThing
    ~Thing() privateThing
    ~ThingsWrapper
    ~Thing() staticThing
    

    相反,我们可以换行 Thing 在一个 WeakReference. 。作为 wrStaticThing 可以进行 GC,我们需要一个延迟加载的方法,为了简洁起见,我省略了该方法。

    class WeakReferenceTest
    {
        public static void Main1()
        {
            var s = new WeakReferenceThing();
            s = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();
            if (WeakReferenceThing.wrStaticThing.IsAlive)
                Console.WriteLine("WeakReference: {0}", 
                    (Thing)WeakReferenceThing.wrStaticThing.Target);
            else 
                Console.WriteLine("WeakReference is dead.");
        }
    }
    class WeakReferenceThing
    {
        public static WeakReference wrStaticThing;
        static WeakReferenceThing()
        { wrStaticThing = new WeakReference(new Thing("wrStaticThing")); }
        ~WeakReferenceThing()
        { Console.WriteLine("~WeakReferenceThing"); }
        //lazy-loaded method to new Thing
    }
    

    请注意下面的输出 wrStaticThing 当 GC 线程被调用时被 GC'ed。

    Thing() wrStaticThing
    ~Thing() wrStaticThing
    ~WeakReferenceThing
    WeakReference is dead.
    
  2. 对于初始化耗时的对象: :您不希望初始化耗时的对象被 GC 回收。您可以保留静态引用来避免这种情况(上面的缺点)或使用 WeakReference.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top