Tengo el siguiente código:
MemoryStream foo(){
MemoryStream ms = new MemoryStream();
// write stuff to ms
return ms;
}
void bar(){
MemoryStream ms2 = foo();
// do stuff with ms2
return;
}
¿Existe alguna posibilidad de que el MemoryStream que he asignado no se elimine de alguna manera más tarde?
Tengo una revisión por pares que insiste en que cierre esto manualmente y no puedo encontrar la información para saber si él tiene un punto válido o no.
c#
.net
memory-leaks
memorystream
Coderer
fuente
fuente
Respuestas:
Si algo es desechable, siempre debe desecharlo. Debería utilizar una
using
declaración en subar()
método para asegurarse de quems2
se elimine.Eventualmente, el recolector de basura lo limpiará, pero siempre es una buena práctica llamar a Dispose. Si ejecuta FxCop en su código, lo marcará como una advertencia.
fuente
No filtrará nada, al menos en la implementación actual.
Llamar a Dispose no limpiará la memoria utilizada por MemoryStream más rápido. Se va a detener el flujo de ser viable para llamadas de lectura / escritura después de la llamada, que pueden o no ser útil para usted.
Si está absolutamente seguro de que nunca desea pasar de un MemoryStream a otro tipo de flujo, no le hará ningún daño no llamar a Dispose. Sin embargo, por lo general es una buena práctica en parte porque si alguna vez haces el cambio se utilizará un flujo diferente, que no quiere ser mordido por un error difícil de encontrar porque usted eligió el camino más fácil desde el principio. (Por otro lado, está el argumento YAGNI ...)
La otra razón para hacerlo de todos modos es que una nueva implementación puede introducir recursos que se liberarían en Dispose.
fuente
IDisposable
es un caso especial que va en contra de las mejores prácticas normales, podría argumentar que es ese caso que no debe hacer hasta que realmente lo necesite, según el YAGNI principio.Sí, hay una fuga , dependiendo de cómo defina LEAK y cuánto DESPUÉS quiera decir ...
Si por fuga te refieres a "la memoria permanece asignada, no disponible para su uso, aunque hayas terminado de usarla" y por último te refieres en cualquier momento después de llamar a dispose, entonces sí, puede haber una fuga, aunque no es permanente (es decir, para la vida del tiempo de ejecución de sus aplicaciones).
Para liberar la memoria administrada utilizada por MemoryStream, debe eliminar la referencia anulando su referencia a ella, de modo que sea elegible para la recolección de basura de inmediato. Si no lo hace, crea una fuga temporal desde el momento en que termina de usarlo, hasta que su referencia se sale del alcance, porque mientras tanto la memoria no estará disponible para su asignación.
El beneficio de la instrucción using (sobre simplemente llamar a dispose) es que puede DECLARAR su referencia en la instrucción using. Cuando finaliza la instrucción using, no solo se llama a dispose, sino que su referencia sale del alcance, anulando efectivamente la referencia y haciendo que su objeto sea elegible para la recolección de basura inmediatamente sin que tenga que recordar escribir el código "reference = null".
Si bien no eliminar la referencia a algo de inmediato no es una fuga de memoria "permanente" clásica, definitivamente tiene el mismo efecto. Por ejemplo, si mantiene su referencia al MemoryStream (incluso después de llamar a dispose), y un poco más abajo en su método intenta asignar más memoria ... la memoria en uso por su flujo de memoria aún referenciado no estará disponible hasta que anule la referencia o salga del alcance, aunque haya llamado a dispose y haya terminado de usarlo.
fuente
No es necesario llamar
.Dispose()
(o envolver conUsing
).La razón por la que llama
.Dispose()
es para liberar el recurso lo antes posible .Piense en términos de, digamos, el servidor de Stack Overflow, donde tenemos un conjunto limitado de memoria y miles de solicitudes ingresan. No queremos esperar la recolección de basura programada, queremos liberar esa memoria lo antes posible para que esté disponible para nuevas solicitudes entrantes.
fuente
FileStream
objetos y otro diferente para losMemoryStream
objetos?Esto ya está respondido, pero solo agregaré que el buen principio antiguo de ocultación de información significa que es posible que en algún momento desee refactorizar:
a:
Esto enfatiza que a las personas que llaman no debería importarles qué tipo de Stream se está devolviendo y hace posible cambiar la implementación interna (por ejemplo, cuando se burlan de las pruebas unitarias).
Entonces tendrá problemas si no ha utilizado Dispose en la implementación de su barra:
fuente
Todos los flujos implementan IDisposable. Envuelva su flujo de memoria en una declaración de uso y estará bien y elegante. El bloque de uso asegurará que su flujo esté cerrado y eliminado pase lo que pase.
dondequiera que llame a Foo, puede hacerlo usando (MemoryStream ms = foo ()) y creo que aún debería estar bien.
fuente
No perderá memoria, pero su revisor de código está en lo correcto al indicar que debe cerrar su transmisión. Es de buena educación hacerlo.
La única situación en la que puede perder memoria es cuando deja accidentalmente una referencia a la secuencia y nunca la cierra. Todavía no está perdiendo memoria, pero está extendiendo innecesariamente la cantidad de tiempo que dice estar usándola.
fuente
Recomendaría envolver el MemoryStream
bar()
en unausing
declaración principalmente por coherencia:.Dispose()
, pero es posible que en algún momento en el futuro lo haga, o usted (o alguien más en su empresa) podría reemplazarlo con su propio MemoryStream personalizado que lo haga, etc.Otra cosa que suelo hacer en casos como
foo()
cuando creo y devuelvo un IDisposable es asegurarme de que cualquier falla entre la construcción del objeto y elreturn
sea detectada por una excepción, elimine el objeto y vuelva a generar la excepción:fuente
Si un objeto implementa IDisposable, debe llamar al método .Dispose cuando haya terminado.
En algunos objetos, Dispose significa lo mismo que Close y viceversa, en ese caso, cualquiera de los dos es bueno.
Ahora, para su pregunta particular, no, no perderá memoria.
fuente
No soy un experto en .net, pero quizás el problema aquí son los recursos, es decir, el identificador del archivo y no la memoria. Supongo que el recolector de basura eventualmente liberará el flujo y cerrará el identificador, pero creo que siempre sería una buena práctica cerrarlo explícitamente, para asegurarse de eliminar el contenido del disco.
fuente
La eliminación de recursos no administrados no es determinista en los lenguajes de recolección de basura. Incluso si llama a Dispose explícitamente, no tiene absolutamente ningún control sobre cuándo se libera realmente la memoria de respaldo. Dispose se llama implícitamente cuando un objeto sale del alcance, ya sea al salir de una instrucción using o al abrir la pila de llamadas de un método subordinado. Dicho todo esto, a veces el objeto puede ser un contenedor para un recurso administrado (por ejemplo, un archivo). Es por eso que es una buena práctica cerrar explícitamente en las declaraciones finalmente o usar la declaración using. Salud
fuente
MemorySteram no es más que una matriz de bytes, que es un objeto administrado. Olvídese de desechar o cerrar, esto no tiene ningún efecto secundario que no sea el de finalización.
Simplemente verifique el constructor o el método de vaciado de MemoryStream en el reflector y quedará claro por qué no necesita preocuparse por cerrarlo o desecharlo, aparte de seguir las buenas prácticas.
fuente