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?
Réponses
Trop de publicités?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.
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;
}
/* ... */
}
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.
Il y a deux raisons pourquoi vous devez utiliser WeakReference
.
-
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 enWeakReference
. 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 destaticObject
.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
enWeakReference
. En tant quewrStaticThing
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.
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
.