2009-11-06 16 views
11

Estoy tratando de escribir un simple Administrador de recursos para el pequeño juego de hobby que estoy escribiendo. Una de las tareas que este administrador de recursos debe hacer es descargar recursos no utilizados. Puedo pensar en hacer esto de dos maneras:C# - Obtener el número de referencias al objeto

  • Cuando un objeto ya no requiere una referencia al recurso, debe llamar a un método del Administrador de recursos para significar que ya no lo está utilizando; o

  • Cuando un objeto ya no requiere una referencia al recurso, simplemente lo establece en NULL. Luego, cuando se solicita al Administrador de recursos que descargue recursos no utilizados, obtiene el recuento de referencias (¿por reflejo?) De cada recurso. Si el recuento de referencia es uno (Resource Manager tiene una referencia al recurso), descargue el recurso.

¿Hay alguna manera de lograr la segunda solución en C#? Gracias.

+0

¿Qué hará su administrador de recursos que no haga el recolector de garbanzos? – CannibalSmith

+1

@CannibalSmith: por lo general, permite que múltiples bits de código reutilicen el recurso (esencialmente, un caché) –

+0

Es para cargar imágenes, asegurándose de que solo se carga una imagen a la vez (no importa cuántas cosas se pidan, solo una versión puede estar en la memoria). –

Respuesta

11

Me parece que puede usar WeakReference desde el administrador de recursos. El GC hará el resto. Tendrás que hacer un poco de casting, pero será simple y funcionará.

class Manager { 
    Dictionary<string, WeakReference> refs = 
     new Dictionary<string, WeakReference>(); 
    public object this[string key] { 
     get { 
      WeakReference wr; 
      if (refs.TryGetValue(key, out wr)) { 
       if(wr.IsAlive) return wr.Target; 
       refs.Remove(key); 
      } 
      return null; 
     } 
     set { 
      refs[key] = new WeakReference(value); 
     } 
    } 
} 
static void Main() { 
    Manager mgr = new Manager(); 
    var obj = new byte[1024]; 
    mgr["abc"] = obj; 

    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); 
    Console.WriteLine(mgr["abc"] != null); // true (still ref'd by "obj") 

    obj = null; 
    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); 
    Console.WriteLine(mgr["abc"] != null); // false (no remaining refs) 
} 
+0

Haría esto :) Una cosa, sin embargo: podría estar equivocado, pero creo que es posible que tenga que obtener la referencia correcta del diccionario y comprobar si es nula antes de devolverla. Si lo hace "if (wr.IsAlive) return wr.Target", nunca hará una referencia fuerte, por lo que IsAlive puede devolver cierto, pero para el momento en que devuelva el valor, es posible que wr.Target se haya recopilado. Aquí hay un ejemplo de código alternativo: http://msdn.microsoft.com/en-us/library/system.weakreference.aspx –

+1

'object' es lo suficientemente fuerte como para evitar la recopilación; o será 'nulo' o fuerte. La persona que llama tendría que convertirlo en una referencia * tipada *, pero ese es un problema diferente ... –

+0

.NET 4.5 tiene una versión genérica de WeakReference; mira esto http://www.philosophicalgeek.com/2014/08/14/prefer-weakreferenceret-to-weakreference / – Logerfo

2

Ya tenemos un administrador de recursos en .NET, llamado el recolector de basura. Entonces, un enfoque muy eficiente es establecer las referencias a nulo y no hacer nada.

Una respuesta más directa: No, no hay forma de obtener las referencias en un objeto.

Es posible que desee estudiar el WeakReference class o utilizar un sistema de almacenamiento en caché.

1

Asegúrese de que el administrador de recursos use WeakReference s en sus recursos. De esta forma, cuando nadie más haga referencia a los recursos, serán elegibles para la recolección de basura.

0

Como ya se ha dicho por otros usuarios, lo que está tratando de lograr ya está hecha por la GC, y se puede ajustar muy bien usar un WeakReference.

Esto implica que en entornos administrados como .NET, Java, etc., esto no es un problema.

Dado que la arquitectura de marco de bajo nivel lo aísla de la gestión de memoria, si aún necesita ese tipo de funcionalidad, le sugiero que revise su propia arquitectura de código, porque significaría que está haciendo algún tipo de mala práctica en la gestión de la memoria

28

Cosas de la pareja. Primero, los objetos no son referencia contados; los esquemas de recuento de referencia tienen el problema de referencia circular, por lo que dos objetos se refieren entre sí pero, de otro modo, son inaccesibles y, por lo tanto, tienen fugas. .NET utiliza un enfoque de marcaje y barrido que no utiliza conteos de ref.

En segundo lugar, aunque la sugerencia de utilizar una referencia débil no es terrible, tampoco es una volcada. Está construyendo un caché por motivos de rendimiento.(Supongo que su investigación cuidadosa, empírica y realista sobre las características de rendimiento de su aplicación ha demostrado convincentemente que es necesaria una estrategia de almacenamiento en caché para lograr un rendimiento aceptable; si ese no es el caso, entonces está tomando estas decisiones prematuramente). la memoria caché debe tener una POLÍTICA sobre cuándo libera sus recursos; de lo contrario, se trata de una pérdida de memoria.

¿Cómo sabe que la política de GC y su política son políticas equivalentes? El GC no se diseñó teniendo en cuenta las necesidades de rendimiento de específicas de. Es decir, fue diseñado para liberar recursos que realmente son basura, no para lograr ningún objetivo de rendimiento particular que tenga en mente. Al delegar la decisión al GC, renuncia a su capacidad de ajustar su política de caché a sus necesidades de rendimiento.

Cuestiones relacionadas