Praktické využití System.WeakReference

hlasů
35

Chápu, co System.WeakReference dělá, ale to, co nedokážu pochopit, je praktickým příkladem toho, co by to mohlo být užitečné pro. Třída sama o sobě se mi zdá být, no, hack. Zdá se mi, že existují i jiné, lepší prostředky k vyřešení problému, kdy je WeakReference používaný v příkladech, které jsem viděl. Jaký je kanonický příklad, kde jste opravdu musím používat WeakReference? Nejsme snaží dostat dál od tohoto typu chování a používání této třídy?

Položena 19/08/2008 v 03:45
zdroj uživatelem
V jiných jazycích...                            


4 odpovědí

hlasů
46

Užitečným příkladem jsou lidé, kteří provozují objektově orientované databáze db4o. Tam, WeakReferences jsou používány jako druh světla vyrovnávací paměti: to udrží vaše objekty v paměti jen tak dlouho, jak vaše aplikace dělá, která vám umožní dát skutečnou paměť na vrcholu.

Další využití by bylo v provádění slabých obsluh událostí. V současné době je jedním velkým zdrojem úniků paměti v aplikacích .NET se zapomněl odstranit rutiny událostí. Např

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

Podívejte se na problém? Ve výše uvedeném fragmentu bude MyForm být udržován při životě v paměti navždy tak dlouho, jak MyApplication žije v paměti. Vytvořit 10 MyForms, zavřete je všechny, budou vaše 10 MyForms být stále v paměti, zůstal živý rutinu události.

Vstoupit WeakReference. Můžete si vytvořit slabý rutiny události pomocí WeakReferences takže someHandler je slabý událost handler pro MyApplication.Foo, tedy upevnění své úniky paměti!

To není jen teorie. Dustin Campbell z blogu DidItWith.NET vykázala implementaci slabých obsluh událostí s využitím System.WeakReference.

Odpovězeno 19/08/2008 v 04:07
zdroj uživatelem

hlasů
12

Používám ho zavést vyrovnávací paměť, kde jsou automaticky do koše nepoužité vstupy:

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;
     }

    /* ... */
   }
Odpovězeno 19/08/2008 v 04:01
zdroj uživatelem

hlasů
2

Já používám slabý odkaz pro státního vedení v mixins. Nezapomeňte, že mixins jsou statické, takže při použití statický objekt připojit stav na non-statické jednu, nikdy nevíte, jak dlouho to bude zapotřebí. Takže místo toho, nechejme si Dictionary<myobject, myvalue>někdy použiji Dictionary<WeakReference,myvalue>, aby se zabránilo mixin z tažením věci příliš dlouho.

Jediným problémem je, že pokaždé, když mám přístup, jsem také kontrolovat mrtvých odkazů a jejich odstranění. Ne že by nikomu ublížit, pokud existují tisíce, samozřejmě.

Odpovězeno 07/12/2008 v 13:04
zdroj uživatelem

hlasů
0

Existují dva důvody, proč byste použili WeakReference.

  1. Místo toho, aby globální objekty deklarovány jako static : Globální objekty jsou deklarovány jako statické pole a statická pole nelze GC'ed (garbage collector), dokud AppDomainje GC'ed. Takže nelze vyloučit výjimky out-of-memory. Místo toho můžeme zabalit globální objekt v WeakReference. I přesto, že WeakReferencesama o sobě je prohlášena za statický objekt odkazuje na bude GC'ed při nedostatku paměti.

    V zásadě použít wrStaticObjectmísto staticObject.

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

    Jednoduchá aplikace, aby prokázal, že statický objekt je garbage collector při AppDomain je.

    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); }
    }
    

    Poznámka z výstupu Níže staticThingje GC'ed na samém konci, i poté, co ThingsWrapperjest - tj GC'ed když AppDomainje GC'ed.

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

    Místo toho můžeme zabalit Thingv WeakReference. Jak je wrStaticThingmožné GC'ed, budeme potřebovat klidná zatížený způsob, který jsem vynechal pro stručnost.

    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
    }
    

    Poznámka z výstupu nižší, než jaká wrStaticThingje GC'ed při GC nit vyvolána.

    Thing() wrStaticThing
    ~Thing() wrStaticThing
    ~WeakReferenceThing
    WeakReference is dead.
    
  2. Pro objekty, které jsou časově náročné pro inicializaci : Nechcete objekty, které jsou časově consusming init být GC'ed. Můžete buď držet statickou reference, aby se zabránilo, aby (s cons shora bodu) nebo použít WeakReference.

Odpovězeno 25/08/2012 v 18:19
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more