[C#] ¿Se crea una pérdida de memoria si MemoryStream en .NET no está cerrado?



Answers

No perderá nada, al menos en la implementación actual.

Calling Dispose no limpiará la memoria utilizada por MemoryStream más rápido. Esto evitará que su transmisión sea viable para las llamadas de Lectura / Escritura después de la llamada, lo que puede o no ser útil para usted.

Si está absolutamente seguro de que nunca desea pasar de un MemoryStream a otro tipo de transmisión, no le hará ningún daño no llamar a Dispose. Sin embargo, en general es una buena práctica, en parte porque si alguna vez cambias para usar un Stream diferente, no querrás ser mordido por un error difícil de encontrar porque eliges la salida fácil desde el principio. (Por otro lado, está el argumento de 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.

Question

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;
}

¿Hay alguna posibilidad de que el MemoryStream que he asignado de alguna manera no se elimine más tarde?

Tengo una revisión por pares que insiste en que cierre manualmente esto, y no puedo encontrar la información para decir si tiene un punto válido o no.




Esto ya está respondido, pero solo agregaré que el principio bien pasado de ocultación de la información significa que en algún momento futuro puede refactorizarse:

MemoryStream foo()
{    
    MemoryStream ms = new MemoryStream();    
    // write stuff to ms    
    return ms;
}

a:

Stream foo()
{    
   ...
}

Esto enfatiza que a las personas que llaman no les debería importar qué tipo de Stream se está devolviendo, y hace posible cambiar la implementación interna (por ejemplo, cuando se burla de las pruebas unitarias).

A continuación, deberá tener problemas si no ha utilizado Eliminar en la implementación de su barra:

void bar()
{    
    using (Stream s = foo())
    {
        // do stuff with s
        return;
    }
}



Yo recomendaría envolver el MemoryStream en bar() en una instrucción using principalmente por consistencia:

  • En este momento MemoryStream no libera memoria en .Dispose() , pero es posible que en algún momento en el futuro lo haga, o usted (u otra persona en su compañía) podría reemplazarlo con su propio MemoryStream personalizado, etc.
  • Ayuda a establecer un patrón en su proyecto para asegurar que todas las transmisiones se eliminen: la línea se dibuja más firmemente diciendo que "todas las transmisiones deben desecharse" en lugar de "algunas de ellas deben eliminarse, pero otras no tienen que ser eliminadas". ...
  • Si alguna vez cambia el código para permitir la devolución de otros tipos de transmisiones, deberá cambiarlo para eliminarlo de todos modos.

Otra cosa que suelo hacer en casos como foo() al crear y devolver un IDisposable es asegurar que cualquier falla entre la construcción del objeto y la return sea ​​atrapada por una excepción, elimine el objeto y vuelva a lanzar la excepción:

MemoryStream x = new MemoryStream();
try
{
    // ... other code goes here ...
    return x;
}
catch
{
    // "other code" failed, dispose the stream before throwing out the Exception
    x.Dispose();
    throw;
}



No soy experto en .net, pero tal vez el problema aquí sean los recursos, es decir, el identificador del archivo y no la memoria. Supongo que el recolector de basura eventualmente liberará la secuencia y cerrará el identificador, pero creo que siempre será una buena práctica cerrarla explícitamente, para asegurarse de que elimine el contenido del disco.




MemorySteram no es más que una matriz de bytes, que es un objeto gestionado. Olvídese de eliminar o cerrar esto no tiene ningún efecto secundario que no sea por encima de la finalización.
Simplemente verifique el método de relleno o relleno de MemoryStream en el reflector y quedará claro por qué no tiene que preocuparse por cerrarlo o desecharlo, solo por cuestiones de buenas prácticas.




No se .Dispose() llamar .Dispose() (o wrapping with Using ).

La razón por la que llama .Dispose() es liberar el recurso lo antes posible .

Piense en términos de, digamos, el servidor , donde tenemos un conjunto limitado de memoria y miles de solicitudes entrando. No queremos esperar para la recolección programada de basura, queremos liberar esa memoria lo antes posible para que esté disponible para nuevas solicitudes entrantes.




Links