2011-05-06 8 views
14

Me gustaría verificar que el código que configura un WeakReference no guarde accidentalmente una referencia fuerte al objeto al que se hace referencia. (Aquí está an example de cómo es fácil hacerlo accidentalmente).Probar/Verificar una WeakReference

¿Es esta la mejor manera de verificar si hay referencias fuertes inadvertidas?

TestObject testObj = new TestObject(); 
WeakReference wr = new WeakReference(testObj); 

// Verify that the WeakReference actually points to the intended object instance. 
Assert.Equals(wr.Target, testObject); 

// Force disposal of testObj; 
testObj = null; 
GC.Collect(); 
// If no strong references are left to the wr.Target, wr.IsAlive will return false. 
Assert.False(wr.IsAlive); 
+0

no se puede esperar GC.Collect(), para obligar a la GC para recoger la basura, es sólo una sugerencia, lo que no podría extraer el objeto. [Colección de memoria automática en .Net] (http://msdn.microsoft.com/en-us/library/f144e03t.aspx) –

+0

¿Le importaría explicar por qué GC.Collect() podría no destruir un objeto que sea elegible para ¿colección? –

+0

Aparece forzosamente en modo predeterminado. Solo cuando está configurado en modo optimizado no funciona, no me di cuenta. –

Respuesta

11

Me puse en contacto con Microsoft sobre esto y aprendí/confirmó que:

  • GC.Collect() fuerza un bloqueo de la recolección de basura .
  • Cuando se ejecuta GC.Collect(), no omitirá misteriosamente los objetos elegibles para la colección. Se siguen reglas predecibles para determinar qué objetos recolectar. Siempre que opere con una comprensión de esas reglas (es decir, cómo se manejan los objetos finalizables), puede forzar la destrucción de un objeto particular aunque la memoria utilizada por el objeto destruido puede o no liberarse.

Más información en mi blog: Can .Net garbage collection be forced?

4

Lo hice ayer. Esto es lo que he tenido que añadir a garantizar la recogida ocurrió antes de su última aserción:

 GC.Collect(); 
     GC.WaitForPendingFinalizers(); 
     GC.WaitForFullGCComplete(); 
     GC.Collect(); 

Si después de este .IsAlive sigue siendo cierto, es probable que todavía hay una referencia fuerte en alguna parte.

A propósito: asegúrese de NO marcar .IsAlive cuando accede a su objetivo WeakReference. Para evitar una condición de carrera entre usted y la comprobación .IsAlive .target, hacer esto:

var r = weakRef.Target AS Something; 
if (r != null) 
{ 
    ... do your thing 
} 
+0

El código * no garantiza * que el objeto se haya recolectado, no se puede forzar el GC de esa manera. Todavía puede usar 'IsAlive' si hace una doble comprobación, es decir, también verifica si hay nulo después de obtener el objetivo. Esto puede ser útil si quieres que el cheque salte temprano, sin tener que hacer el casting si es seguro que no hay nada para transmitir. – Guffa

+3

GC.Collect() preforma una colección de bloqueo: el método solo regresa después de que la colección se haya completado, por lo que la llamada a GC.WaitForFullGCComplete() debería ser innecesaria. GC.WaitForFullGCComplete() está destinado para su uso en un escenario diferente. –

Cuestiones relacionadas