¿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 deshacerse de cualquier instancia de objetos que implementen la IDisposable
interfaz para liberar algunos recursos, aunque el objeto todavía puede ser algo después de ser eliminado (de ahí la isDisposed
propiedad en los formularios), por lo que supongo que aún puede residir en memoria o al menos en parte?
También sé que cuando un objeto se sale del alcance, se marca para su recolección y está listo para la próxima pasada del recolector de basura (aunque esto puede llevar tiempo).
Entonces, con esto en mente, ¿lo configurará para null
acelerar el sistema liberando la memoria, ya que no tiene que resolver que ya no está dentro del alcance y hay algún efecto secundario negativo?
Los artículos de MSDN nunca hacen esto en ejemplos y actualmente lo hago ya que no puedo ver el daño. Sin embargo, me he encontrado con una mezcla de opiniones, por lo que cualquier comentario es útil.
Respuestas:
Karl es absolutamente correcto, no hay necesidad de establecer objetos en nulo después de su uso. Si un objeto se implementa
IDisposable
, solo asegúrese de llamarIDisposable.Dispose()
cuando haya terminado con ese objeto (envuelto en untry
...finally
o unusing()
bloque). Pero incluso si no recuerda llamarDispose()
, el método finalizador en el objeto debería estar llamandoDispose()
por usted.Pensé que este era un buen trato:
y esto
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 Modelo de memoria de Windows y el libro de Richters CLR a través de C # capítulo 20 tiene un gran tratamiento:
fuente
Otra razón para evitar establecer objetos en nulo cuando haya terminado con ellos es que en realidad puede mantenerlos vivos por más tiempo.
p.ej
permitirá que el objeto referido por someType sea GC'd después de la llamada a "DoSomething" pero
a veces puede mantener vivo el objeto 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 los mismos.
fuente
GC.KeepAlive(someType);
See ericlippert.com/2013/06/10/construction-destructionNo, no objetos nulos. 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 null no hará nada, excepto ensuciar su código.
fuente
También:
fuente
En general, no es necesario anular objetos después del 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 usar el objeto desechado. Los errores del siguiente tipo pueden ser dolorosos:
Es bueno anular el campo después de desecharlo 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 el futuro (dependiendo exactamente de lo que haga DoSomething).
fuente
.Dispose()
. Si lo encuentra, no está utilizando IDisposable correctamente. El único uso para un objeto desechable debe estar dentro de los límites de un bloque de uso. Y después de usar el bloque, ya ni siquiera tiene acceso a élmyField
. Y dentro del bloque de uso,null
no es necesario establecerlo, el bloque de uso dispondrá el objeto por usted.Lo más probable es que su código no esté suficientemente estructurado si siente la necesidad de
null
variables.Hay varias formas de limitar el alcance de una variable:
Como lo menciona Steve Tranby
Del mismo modo, simplemente puede usar llaves:
Me parece que el uso de llaves sin ningún "encabezado" para realmente limpiar el código y ayudar a que sea más comprensible.
fuente
El único momento en que debe establecer una variable como nulo es cuando la variable no se sale del alcance y ya no necesita los datos asociados a ella. De lo contrario no hay necesidad.
fuente
En general, no es necesario establecerlo en nulo. Pero suponga que tiene una funcionalidad Restablecer en su clase.
Entonces puede hacerlo, porque no desea llamar a dispose dos veces, ya que parte de Dispose puede no implementarse correctamente y generar la excepción System.ObjectDisposed.
fuente
Este tipo de "no es necesario establecer objetos en nulo después del uso" no es del todo exacto. Hay veces que necesita NULL la variable después de desecharla.
Sí, SIEMPRE debe llamar
.Dispose()
o llamar.Close()
a cualquier cosa que tenga cuando haya terminado. Ya se trate de identificadores de archivos, conexiones de bases de datos u objetos desechables.Aparte de eso, está el patrón muy práctico de LazyLoad.
Decir que tengo y crea una instancia
ObjA
declass A
.Class A
tiene una propiedad pública llamadaPropB
declass B
.Internamente,
PropB
usa la variable privada de_B
y por defecto es nulo. CuandoPropB.Get()
se utiliza, se comprueba si_PropB
es nulo y si es así, abre los recursos necesarios para crear instancias de unB
a_PropB
. Luego vuelve_PropB
.Según mi experiencia, este es un truco realmente útil.
Donde entra la necesidad de anular es si restablece o cambia A de alguna manera de la que el contenido
_PropB
era hijo de los valores anterioresA
, deberá Eliminar Y_PropB
anular para que LazyLoad pueda restablecer para obtener el valor correcto SI el código lo requiereSi solo lo hace
_PropB.Dispose()
y poco después espera que la comprobación nula para LazyLoad tenga éxito, no será nula y verá datos obsoletos. En efecto, debe anularlo despuésDispose()
solo para estar seguro.Seguramente desearía que fuera de otra manera, pero ahora tengo un código que muestra este comportamiento después de un
Dispose()
encendido_PropB
y fuera de la función de llamada que hizo la Disposición (y, por lo tanto, casi fuera del alcance), el accesorio privado aún no es nulo, y los datos obsoletos siguen ahí.Eventualmente, la propiedad dispuesta se anulará, pero eso no ha sido determinista desde mi perspectiva.
La razón principal, como alude dbkk, es que el contenedor padre (
ObjA
conPropB
) mantiene la instancia_PropB
dentro del alcance, a pesar deDispose()
.fuente
Hay algunos casos en los que tiene sentido hacer referencias nulas. Por ejemplo, cuando está escribiendo una colección, como una cola prioritaria, y según su contrato, no debe mantener esos objetos vivos para el cliente después de que el cliente los haya eliminado de la cola.
Pero este tipo de cosas solo importa en colecciones de larga vida. Si la cola no va a sobrevivir al final de la función en la que se creó, entonces importa mucho menos.
En general, realmente no deberías molestarte. Deje que el compilador y GC hagan su trabajo para que pueda hacer el suyo.
fuente
Eche un vistazo a este artículo también: http://www.codeproject.com/KB/cs/idisposable.aspx
En su mayor parte, establecer un objeto en nulo no tiene ningún efecto. El único momento en el que debe asegurarse de hacerlo es si está trabajando con un "objeto grande", que tiene un tamaño mayor a 84K (como mapas de bits).
fuente
Stephen Cleary explica muy bien en esta publicación: ¿Debería establecer variables en nulo para ayudar a la recolección de basura?
Dice:
Lo importante que debemos considerar son los campos estáticos .
Conclusión:
fuente
Creo que por el diseño de los implementadores de GC, no se puede acelerar GC con anulación. Estoy seguro de que preferiría que no se preocupe con la forma / GC cuando se ejecuta - tratarlo como esta omnipresente Ser proteger y velar y hacia fuera para usted ... (arcos cabeza hacia abajo, levanta el puño al cielo) .. .
Personalmente, a menudo establezco explícitamente las variables en nulas cuando termino con ellas como una forma de auto documentación. No declaro, uso, luego lo configuro como nulo más tarde: lo anulo inmediatamente después de que ya no son necesarios. Estoy diciendo, explícitamente: "Ya terminé oficialmente contigo ... vete ..."
¿La anulación es necesaria en un lenguaje GC'd? No. ¿Es útil para el GC? Tal vez sí, tal vez no, no lo sé con certeza, por diseño realmente no puedo controlarlo, e independientemente de la respuesta de hoy con esta o aquella versión, las futuras implementaciones de GC podrían cambiar la respuesta más allá de mi control. Además, si se optimiza la anulación, es poco más que un comentario elegante, por así decirlo .
Me imagino que si aclara mi intención al próximo tonto pobre que sigue mis pasos, y si "podría" ayudar a GC a veces, entonces vale la pena para mí. Principalmente me hace sentir ordenado y claro, y a Mongo le gusta sentirse ordenado y claro. :)
Lo veo así: los lenguajes de programación existen para permitir que las personas den a otras personas una idea de intención y un compilador solicite un trabajo sobre qué hacer: el compilador convierte esa solicitud en un idioma diferente (a veces varios) para una CPU. la (s) CPU (s) podría (n) desear qué idioma usó, su configuración de pestañas, comentarios, énfasis estilísticos, nombres de variables, etc. 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 declaración de trabajo. Lo que ves no es lo que obtienes, sí, incluso en lenguaje ensamblador.
Entiendo que la mentalidad de "cosas innecesarias" (como líneas en blanco) "no son más que ruido y código desordenado". Ese era yo al principio de mi carrera; Lo entiendo totalmente. En este momento me inclino hacia lo que aclara el código. No es como si estuviera agregando incluso 50 líneas de "ruido" a mis programas, 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 corresponde porque la memoria no es parte de the GC'd Universe, espero que todos lo entiendan. El resto del tiempo con los lenguajes GC'd es una cuestión de estilo más que 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 adecuadamente; encerar, encerar; inhala exhala; y por todo lo demás digo: si se siente bien, hazlo. Su kilometraje puede variar ... como debería ...
fuente
Creo que volver a poner algo en nulo es desordenado. Imagine un escenario en el que el elemento que se está configurando ahora está expuesto, por ejemplo, a través de la propiedad. Ahora, de alguna manera, algún fragmento de código usa accidentalmente esta propiedad después de que se elimina el elemento, obtendrá una excepción de referencia nula que requiere un poco de investigación para descubrir exactamente qué está sucediendo.
Creo que el marco desechable permitirá lanzar ObjectDisposedException, que es más significativo. No volver a establecerlos en nulo sería mejor que por ese motivo.
fuente
Algunos objetos suponen el
.dispose()
método que obliga a eliminar el recurso de la memoria.fuente