代码之家  ›  专栏  ›  技术社区  ›  Peter Meyer

系统的实际使用。弱参考

  •  39
  • Peter Meyer  · 技术社区  · 18 年前

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

    4 回复  |  直到 18 年前
        1
  •  46
  •   Judah Gabriel Himango    18 年前

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

    另一个用途是实现弱事件处理程序。目前,内存泄漏的一个主要来源。NET应用程序忘记删除事件处理程序。例如

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

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

    输入WeakReference。您可以使用WeakReferences构建弱事件处理程序,使someHandler成为MyApplication的弱事件处理函数。Foo,从而修复你的内存泄漏!

    这不仅仅是理论。来自DidItWith的达斯汀·坎贝尔。NET博客发布 an implementation of weak event handlers 使用系统。弱参考。

        2
  •  13
  •   Mark Cidade    18 年前

    我用它来实现一个缓存,其中未使用的条目会被自动垃圾回收:

    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;
         }
    
        /* ... */
       }
    
        3
  •  2
  •   Dmitri Nesteruk    17 年前

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

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

        4
  •  0
  •   hIpPy    14 年前

    您使用的原因有两个 WeakReference .

    1. 而不是声明为静态的全局对象 :全局对象被声明为静态字段,在 AppDomain 是GC的。所以你有内存不足的风险。相反,我们可以将全局对象包装在 弱参考 尽管 弱参考 它本身被声明为静态,当内存不足时,它指向的对象将被GC删除。

      基本上,使用 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在以下情况下终止 应用程序域 是GC的。

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

      相反,我们可以包装 Thing 在一个 弱参考 .As 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的。您可以保留静态引用以避免这种情况(使用上述缺点),也可以使用 弱参考 .