Establecer objetos en Null / Nothing después de su uso en .NET

¿Debería establecer todos los objetos en null ( Nothing en VB.NET) una vez que haya terminado con ellos?

Entiendo que en .NET es esencial disponer de instancias de objetos que implementen la interfaz IDisposable para liberar algunos recursos, aunque el objeto aún puede ser algo después de que se isDisposed (de ahí la propiedad isDisposed en formularios), así que supongo que puede aún residen en la memoria o al menos en parte?

También sé que cuando un objeto se sale del scope, se marca para que esté listo para el próximo pase del recolector de basura (aunque esto puede llevar tiempo).

Entonces, con esto en mente, establecerlo en null acelerará el sistema liberando la memoria, ya que no tiene que resolverse que ya no está dentro del scope y ¿son malos efectos secundarios?

Los artículos de MSDN nunca hacen esto en ejemplos y actualmente lo hago porque no puedo ver el daño. Sin embargo, he encontrado una mezcla de opiniones, por lo que cualquier comentario es útil.

Karl tiene toda la razón, no hay necesidad de establecer objetos para nulos después del uso. Si un objeto implementa IDisposable , solo asegúrate de llamar a IDisposable.Dispose() cuando hayas terminado con ese objeto (envuelto en un tryfinally , o un bloque using() ). Pero incluso si no recuerda llamar a Dispose() , el método del finalizador en el objeto debería llamar a Dispose() por usted.

Pensé que este era un buen tratamiento:

Buscando en IDisposable

y esto

Comprensión IDisposable

No tiene sentido intentar adivinar el GC y sus estrategias de gestión porque es autoajustable y opaco. Hubo una buena discusión sobre el funcionamiento interno con Jeffrey Richter en Dot Net Rocks aquí: Jeffrey Richter en el Windows Memory Model y el libro de Richters CLR a través de C # capítulo 20 tiene un gran tratamiento:

Otra razón para evitar el establecimiento de objetos a nulo cuando haya terminado con ellos es que realmente puede mantenerlos vivos durante más tiempo.

p.ej

 void foo() { var someType = new SomeType(); someType.DoSomething(); // someType is now eligible for garbage collection // ... rest of method not using 'someType' ... } 

permitirá que el objeto referido por someType sea GC’d después de la llamada a “DoSomething” pero

 void foo() { var someType = new SomeType(); someType.DoSomething(); // someType is NOT eligible for garbage collection yet // because that variable is used at the end of the method // ... rest of method not using 'someType' ... someType = null; } 

a veces puede mantener el objeto vivo hasta el final del método. El JIT generalmente optimiza la asignación a nulo , por lo que ambos bits de código terminan siendo el mismo.

No, no anules objetos. Puede consultar http://codebetter.com/blogs/karlseguin/archive/2008/04/27/foundations-of-programming-pt-7-back-to-basics-memory.aspx para obtener más información, pero configurar las cosas anular no hará nada, excepto ensuciar su código.

También:

 using(SomeObject object = new SomeObject()) { // do stuff with the object } // the object will be disposed of 

En general, no hay necesidad de anular objetos después de su uso, pero en algunos casos creo que es una buena práctica.

Si un objeto implementa IDisposable y se almacena en un campo, creo que es bueno anularlo, solo para evitar el uso del objeto eliminado. Los errores del siguiente tipo pueden ser dolorosos:

 this.myField.Dispose(); // ... at some later time this.myField.DoSomething(); 

Es bueno anular el campo después de tirarlo, y obtener un NullPtrEx justo en la línea donde el campo se usa nuevamente. De lo contrario, podría encontrarse con algún error críptico en la línea (dependiendo de lo que DoSomething haga).

Lo más probable es que su código no esté lo suficientemente estructurado si siente la necesidad de null variables.

Hay varias formas de limitar el scope de una variable:

Como lo mencionó Steve Tranby

 using(SomeObject object = new SomeObject()) { // do stuff with the object } // the object will be disposed of 

Del mismo modo, puede simplemente usar corchetes:

 { // Declare the variable and use it SomeObject object = new SomeObject() } // The variable is no longer available 

Encuentro que usar corchetes sin ningún “encabezado” para realmente limpiar el código y ayudar a que sea más comprensible.

La única vez que debe establecer que una variable sea nula es cuando la variable no se salga del scope y ya no necesite los datos asociados con ella. De lo contrario, no hay necesidad.

En general, no es necesario establecer nulo. Pero supongamos que tiene una funcionalidad de reinicio en su clase.

Entonces podría hacerlo, porque no desea llamar a disponer dos veces, ya que parte del Dispose puede no implementarse correctamente y lanzar la excepción System.ObjectDisposed.

 private void Reset() { if(_dataset != null) { _dataset.Dispose(); _dataset = null; } //..More such member variables like oracle connection etc. _oraConnection } 

este tipo de “no hay necesidad de configurar objetos para anular después del uso” no es del todo exacto. Hay ocasiones en que necesita NULL la variable después de eliminarla.

Sí, SIEMPRE debe llamar a .Dispose() o .Close() en cualquier elemento que lo tenga cuando haya terminado. Ya sean manejadores de archivos, conexiones de bases de datos u objetos desechables.

Separado de eso es el patrón muy práctico de LazyLoad.

Digamos que tengo e instanciado ObjA de class A Class A tiene una propiedad pública llamada PropB de class B

Internamente, PropB usa la variable privada de _B y se predetermina a nulo. Cuando se utiliza PropB.Get() , comprueba si _PropB es nulo y, en caso _PropB , abre los recursos necesarios para crear una instancia de B en _PropB . Luego devuelve _PropB .

Para mi experiencia, este es un truco realmente útil.

Donde entra la necesidad de null es si reinicia o cambia A de alguna manera que el contenido de _PropB era el hijo de los valores previos de A , tendrá que descartar Y _PropB para que LazyLoad pueda restablecerse para recuperar el valor correcto SI el código lo requiere.

Si solo hace _PropB.Dispose() y poco después espera que la verificación nula de LazyLoad tenga éxito, no será nulo, y estará buscando datos obsoletos. En efecto, debe anularlo después de Dispose() solo para estar seguro.

Desearía que fuera de otra manera, pero ahora tengo un código que muestra este comportamiento después de un Dispose() en un _PropB y fuera de la función de llamada que hizo el Dispose (y por lo tanto casi fuera del scope), el prop privado aún no está ‘nulo, y los datos obsoletos todavía están allí.

Finalmente, la propiedad eliminada se anulará, pero eso no ha sido determinista desde mi punto de vista.

El motivo principal, como alude dbkk es que el contenedor primario ( ObjA con PropB ) mantiene la instancia de _PropB en el scope, a pesar del Dispose() .

Hay algunos casos en los que tiene sentido para las referencias nulas. Por ejemplo, cuando está escribiendo una colección, como una cola de prioridad, y según su contrato, no debe mantener esos objetos vivos para el cliente una vez que el cliente los haya eliminado de la cola.

Pero este tipo de cosas solo importa en colecciones de larga duración. Si la cola no va a sobrevivir al final de la función en la que se creó, entonces importa mucho menos.

En general, no deberías molestarte. Deje que el comstackdor y GC hagan su trabajo para que pueda hacer el suyo.

Eche un vistazo a este artículo también: http://www.codeproject.com/KB/cs/idisposable.aspx

En su mayor parte, establecer un objeto como nulo no tiene ningún efecto. La única vez que debe asegurarse de hacerlo es si está trabajando con un “objeto grande”, que es uno de tamaño superior a 84K (como mapas de bits).

Creo que por diseño de los implementadores de GC, no se puede acelerar GC con anulación. Estoy seguro de que preferirían que no te preocupes por cómo y cuándo funciona GC, trátalo como este Ser omnipresente que te protege y vigila por ti … (inclina la cabeza hacia abajo, levanta el puño hacia el cielo). .

Personalmente, a menudo establezco explícitamente las variables como nulas cuando termino con ellas como una forma de auto-documentación. No declaro, uso, y luego configuro nulo más tarde; anulo inmediatamente después de que ya no se necesitan. Estoy diciendo, explícitamente, “Ya terminé oficialmente contigo … ya te fuiste …”

¿Es necesario anular en un lenguaje GC? No. ¿Es útil para el GC? Tal vez sí, tal vez no, no estoy seguro, por diseño realmente no puedo controlarlo, y sin importar la respuesta de hoy con esta versión o esa, las futuras implementaciones de GC podrían cambiar la respuesta más allá de mi control. Además, si / nulling se optimiza, es poco más que un comentario elegante, si se quiere.

Me imagino que si mi intención es más clara para el siguiente tonto pobre que sigue mis pasos, y si “podría” potencialmente ayudar a GC a veces, entonces vale la pena para mí. En general, me hace sentir limpio y ordenado, y a Mongo le gusta sentirse ordenado y claro. 🙂

Lo veo así: los lenguajes de progtwigción existen para permitir que las personas den a otras personas una idea de bash y un comstackdor una solicitud de trabajo de qué hacer; el comstackdor convierte esa solicitud en un idioma diferente (a veces varios) para una CPU – la (s) CPU (s) podría indicarle qué idioma usó, la configuración de sus tabs, comentarios, énfasis estilístico, nombres de variables, etc. – una CPU es todo sobre el flujo de bits que le dice qué registros y códigos de operación y ubicaciones de memoria mezclar. Muchas cosas escritas en el código no se convierten en lo que consume la CPU en la secuencia que especificamos. Nuestro C, C ++, C #, Lisp, Babel, ensamblador o lo que sea es teoría en lugar de realidad, escrito como una statement de trabajo. Lo que ves no es lo que obtienes, sí, incluso en lenguaje ensamblador.

Entiendo que el modo de pensar de “cosas innecesarias” (como líneas en blanco) “no es más que ruido y código desordenado”. Ese fui yo al principio de mi carrera; Lo entiendo totalmente. En esta coyuntura me inclino hacia lo que hace que el código sea más claro. No es como si estuviera agregando incluso 50 líneas de “ruido” a mis progtwigs, son algunas líneas aquí o allá.

Hay excepciones a cualquier regla. En escenarios con memoria volátil, memoria estática, condiciones de carrera, singletons, uso de datos “obsoletos” y todo ese tipo de podredumbre, eso es diferente: NECESITA administrar su propia memoria, bloqueando y anulando como apropos porque la memoria no es parte de el Universo GC’d – ojalá todos entiendan eso. El rest del tiempo con los lenguajes de GC es una cuestión de estilo en lugar de necesidad o un aumento de rendimiento garantizado.

Al final del día, asegúrese de comprender qué es elegible para GC y qué no; bloquear, desechar y anular apropiadamente; encerar, encerar; inhala exhala; y para todo lo demás, digo: si se siente bien, hazlo. Su kilometraje puede variar … como debería …

Algunos objetos suponen el método .dispose() que fuerza al recurso a eliminarse de la memoria.