yugioh traduccion recolector net invocar example español collector collection basura .net garbage-collection

.net - traduccion - Uso práctico de System.WeakReference



invocar garbage collector c# (4)

Utilizo una referencia débil para mantener el estado en mixins. Recuerde, las mixinas son estáticas, por lo que cuando usa un objeto estático para adjuntar el estado a uno no estático, nunca sabe cuánto tiempo se requerirá. Entonces, en lugar de mantener un Dictionary<myobject, myvalue> guardo un Dictionary<WeakReference,myvalue> para evitar que el mixin arrastre cosas por mucho tiempo.

El único problema es que cada vez que hago un acceso, también verifico las referencias muertas y las elimino. No es que lastimen a nadie, a menos que haya miles, por supuesto.

Entiendo lo que hace System.WeakReference , pero lo que no puedo entender es un ejemplo práctico de para qué podría ser útil. La clase en sí me parece, bueno, un truco. Me parece que hay otros medios mejores para resolver un problema donde se usa una WeakReference en ejemplos que he visto. ¿Cuál es el ejemplo canónico de dónde tienes que usar realmente WeakReference? ¿No estamos tratando de alejarnos más de este tipo de comportamiento y uso de esta clase?


Un ejemplo útil es la gente que ejecuta la base de datos orientada a objetos DB4O. Allí, WeakReferences se usa como un tipo de caché claro: mantendrá tus objetos en la memoria solo mientras tu aplicación lo haga, permitiéndote poner un caché real en la parte superior.

Otro uso sería en la implementación de manejadores de eventos débiles. Actualmente, una gran fuente de pérdidas de memoria en las aplicaciones .NET es olvidarse de eliminar los manejadores de eventos. P.ej

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

Ver el problema? En el fragmento de arriba, MyForm se mantendrá vivo en la memoria siempre y cuando MyApplication esté vivo en la memoria. Cree 10 MyForms, ciérrelos todos, sus 10 MyForms seguirán estando en la memoria, mantenidos vivos por el controlador de eventos.

Ingrese WeakReference. Puedes construir un manejador de eventos débiles usando WeakReferences para que someHandler sea un manejador de eventos débiles para MyApplication.Foo, ¡así arreglando tus pérdidas de memoria!

Esto no es solo teoría. Dustin Campbell del blog DidItWith.NET publicó una implementación de manejadores de eventos débiles utilizando System.WeakReference.


Lo uso para implementar un caché donde las entradas no utilizadas son recolectadas de forma automática.

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; } /* ... */ }


Hay dos razones por las que usaría WeakReference .

  1. En lugar de objetos globales declarados como estáticos : los objetos globales se declaran como campos estáticos y los campos estáticos no se pueden someter a GC (recolección de basura) hasta que el dominio de la aplicación sea GC. Entonces arriesgas las excepciones de falta de memoria. En cambio, podemos envolver el objeto global en una WeakReference . Aunque la propia WeakReference se declara estática, el objeto al que apunta recibirá GC cuando la memoria sea baja.

    Básicamente, use wrStaticObject lugar de staticObject .

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

    Aplicación simple para demostrar que el objeto estático se recolecta basura cuando AppDomain es.

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

    Nota del resultado debajo de staticThing es GC''ed al final incluso después de ThingsWrapper es - es decir GC''ed cuando AppDomain está GC''ed.

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

    En su lugar, podemos ajustar Thing en WeakReference . Como wrStaticThing puede ser sometido a GC, necesitaremos un método de carga wrStaticThing que he omitido por brevedad.

    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 }

    Tenga en cuenta a partir de la salida que wrStaticThing está en GC cuando se invoca thread de GC.

    Thing() wrStaticThing ~Thing() wrStaticThing ~WeakReferenceThing WeakReference is dead.

  2. Para objetos que consumen mucho tiempo para inicializarse : no quiere que los objetos que conspiran en el tiempo para iniciar sean GC. Puede conservar una referencia estática para evitar eso (con contras desde el punto anterior) o usar WeakReference .