36 votes

Utilisation pratique de System.WeakReference

Je comprends ce Système.WeakReference fait, mais ce que je n'arrive pas à comprendre, c'est un exemple concret de ce que pourrait être utile pour. La classe elle-même me semble être, ainsi, un hack. Il me semble qu'il existe d'autres, le meilleur moyen de résoudre un problème dans lequel un WeakReference est utilisé dans les exemples que j'ai vu. Quelle est l'exemple canonique de l'endroit où vous avez vraiment utiliser un WeakReference? Ne sommes-nous pas essayer d'obtenir plus loin à l'écart de ce type de comportement et de l'utilisation de cette classe?

47voto

Judah Himango Points 27365

Un bon exemple est le gars qui courent DB4O orientée objet base de données. Là, WeakReferences sont utilisés comme une sorte de lumière de cache: il permettra de garder vos objets en mémoire aussi longtemps que votre application n', vous permettant de placer un vrai cache sur le dessus.

Une autre utilisation serait dans la mise en œuvre de la faiblesse des gestionnaires d'événements. Actuellement, une grande source de fuites de mémoire dans .NET applications, c'est d'oublier de supprimer des gestionnaires d'événements. E. g.

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

Vous voyez le problème? Dans l'extrait ci-dessus, MyForm sera gardé vivant dans la mémoire pour toujours tant que MyApplication est vivante dans la mémoire. Créer 10 MyForms, tout fermer, votre 10 MyForms sera encore dans la mémoire, maintenu en vie par le gestionnaire d'événements.

Entrez WeakReference. Vous pouvez construire une faible gestionnaire d'événement à l'aide de WeakReferences de sorte que someHandler est un faible gestionnaire d'événement pour MyApplication.Toto, ce qui permet de corriger vos fuites de mémoire!

Ce n'est pas seulement de la théorie. Dustin Campbell, de la DidItWith.NET blog posté de mise en œuvre de la faiblesse des gestionnaires d'événements à l'aide de Système.WeakReference.

13voto

Mark Cidade Points 53945

Je l'utilise pour implémenter un cache où les entrées inutilisées sont automatiquement récupérées:

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

    /* ... */
   }
 

2voto

Dmitri Nesteruk Points 7669

J'utilise la faiblesse de référence de l'état en gardant à l'mixin. Rappelez-vous, mixin sont statiques, de sorte que lorsque vous utilisez un objet statique à attacher de l'état à un non-statique, vous ne savez jamais combien de temps il sera nécessaire. Donc, au lieu de garder un Dictionary<myobject, myvalue> - je garder un Dictionary<WeakReference,myvalue> pour éviter le mixin de faire glisser des choses trop longtemps.

Le seul problème est que chaque fois que je fais un accès, je vérifie également pour les morts, les références et les supprimer. Non pas qu'ils ont fait de mal à personne, sauf si il y a des milliers, bien sûr.

0voto

hIpPy Points 727

Il y a deux raisons pourquoi vous devez utiliser WeakReference.

  1. Au lieu de cela des objets globaux déclarés comme statique: Global objets sont déclarés comme les champs statiques et les champs statiques ne peuvent pas être GC ed (garbage collector) jusqu'à ce que l' AppDomain GC ed. Donc vous risquez de mémoire exceptions. Au lieu de cela, nous pouvons conclure que l'objet global en WeakReference. Même si l' WeakReference lui-même est déclarée statique, l'objet de points sera GC ed lorsque la mémoire est faible.

    Fondamentalement, il faut utiliser wrStaticObject au lieu de staticObject.

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

    Application Simple de prouver que l'objet statique est des ordures collectées lors de l'AppDomain est.

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

    Remarque à partir de la sortie ci-dessous staticThing GC est ed à la fin, même après l' ThingsWrapper est - c'est à dire GC ed lorsqu' AppDomain GC ed.

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

    Au lieu de cela nous pouvons conclure Thing en WeakReference. En tant que wrStaticThing peut être GC ed, nous allons avoir besoin d'un chargement paresseux méthode que j'ai laissé de côté pour des raisons de concision.

    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
    }
    

    Note de la sortie ci-dessous que wrStaticThing GC ed lorsque GC thread est invoquée.

    Thing() wrStaticThing
    ~Thing() wrStaticThing
    ~WeakReferenceThing
    WeakReference is dead.
    
  2. Pour les objets qui sont beaucoup de temps pour initialiser: Vous ne voulez pas les objets qui sont consusming à init pour être GC ed. Vous pouvez soit garder une référence statique pour éviter que (avec les inconvénients du point ci-dessus) ou d'utiliser WeakReference.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X