2012-01-03 4 views
11

Tengo un montón de métodos que toman el WPF WriteableBitmap y leen de su BackBuffer directamente, usando un código inseguro.¿Se requiere GC.KeepAlive aquí, o puedo confiar en los locales y en los argumentos para mantener vivo un objeto?

No está del todo claro si debo utilizar GC.KeepAlive cada vez que hago algo como esto:

int MyMethod(WriteableBitmap bmp) 
{ 
    return DoUnsafeWork(bmp.BackBuffer); 
} 

Por un lado, sigue existiendo una referencia a bmp en la pila MyMethod 's. Por otro lado, parece depender de los detalles de implementación; esto podría compilarse a una llamada final, por ejemplo, sin guardar referencia en bmp en el momento en que se ingresa el DoUnsafeWork.

Del mismo modo, imaginemos el siguiente código hipotética:

int MyMethod() 
{ 
    WriteableBitmap bmp1 = getABitmap(); 
    var ptr = bmp.BackBuffer; 
    WriteableBitmap bmp2 = getABitmap(); 
    return DoUnsafeWork(ptr, bmp2); 
} 

En teoría, una referencia a bmp1 permanece en la pila hasta que se devuelve el método, pero una vez más, parece que el uso de un detalle de implementación. Seguramente el compilador es libre de combinar bmp1 y bmp2 porque nunca están vivos al mismo tiempo, e incluso si el compilador nunca hace eso seguramente el JITter todavía puede, y probablemente lo hace (por ejemplo, al almacenarlos a ambos en el mismo registro, primero uno, luego el otro).

Entonces, en general, ¿debo confiar en que los locales/argumentos son referencias válidas para un objeto, o debería usar siempre GC.KeepAlive para garantizar la corrección?

Esto es especialmente desconcertante ya que, al parecer, FxCop thinks GC.KeepAlive is always bad.

+2

Lectura relacionada: [? ¿Cuándo necesito usar 'GC.KeepAlive'] (http://blogs.msdn.com/b/oldnewthing/archive/2010/08/13/ 10049634.aspx) y [¿Cuándo se vuelve un objeto disponible para la recolección de basura?] (Http://blogs.msdn.com/b/oldnewthing/archive/2010/08/10/10048149.aspx) del blog de Raymond Chen. –

+0

@DanielPryden Excelente enlace; Busqué en Google el primero pero no el segundo antes de preguntar. Además de lo que ya he preguntado, explica que 'this' tampoco mantiene vivo el objeto actual. –

Respuesta

12

¿Debo confiar en que los locales/argumentos son referencias válidas para un objeto?

No. Su análisis es correcto; el jitter está totalmente dentro de su derecho de decirle al recolector de basura que los contenidos del local están muertos en el momento en que ya no están en uso por el código administrado.

¿Debería siempre utilizar GC.KeepAlive para garantizar la corrección?

Sí. Para eso es para eso.

0

Si ha llamado WriteableBitmap.Lock antes de recuperar el búfer, entonces WriteableBitmap debe estar anclado y la memoria subyacente no se moverá. Al menos esa es mi interpretación de WriteableBitmapAPI.

He usado WriteableBitmap exhaustivamente, en particular la biblioteca de código abierto WriteableBitmapEx en codeplex (revelación, he contribuido una vez a esta biblioteca, pero no es mi proyecto). Esto utiliza el patrón de bloqueo/acceso Backbuffer (repetidamente)/desbloquear/invalidar para dibujar. Nunca he tenido un problema con este patrón, aunque el backbuffer IntPtr se almacena en una estructura y se pasa alrededor de la aplicación.

Saludos,

+0

Sabía que podría aparecer Lock/Unlock, y podría estar siendo malo para no bloquearlo mientras estoy leyendo (la documentación solo explica por qué debe bloquear mientras escribe). Sin embargo, esto no tiene nada que ver con la fijación del puntero; 'BackBuffer' está garantizado para ser reparado, como por MSDN. –

+0

Hmm, no lo sabía, ¡gracias! Haré algunas pruebas en mi propio código ya que Bloquear/Desbloquear es una operación costosa :) En cuanto a su pregunta, he visto a GC hacer cosas raras como recopilar cosas que todavía están en el alcance pero que ya no se usan, específicamente en modo de lanzamiento . ¿Obtienes resultados diferentes en Release o Debug con tu ejemplo de código? –

+0

La pregunta es teórica; Todavía no he visto ninguna mala conducta real con este tipo de código. De hecho, no me sorprendería si resulta que siempre funciona en el compilador/JIT actual. –

Cuestiones relacionadas