Eu tenho o seguinte 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 alguma chance de o MemoryStream que aloquei falhar ao ser descartado posteriormente?
Eu tenho uma revisão por pares insistindo que eu feche manualmente, e não consigo encontrar a informação para dizer se ele tem um ponto válido ou não.
c#
.net
memory-leaks
memorystream
Coderer
fonte
fonte
Respostas:
Se algo for descartável, você deve sempre descartá-lo. Você deve usar uma
using
instrução em seubar()
método para garantir quems2
seja descartado.Eventualmente, ele será limpo pelo coletor de lixo, mas é sempre uma boa prática chamar Dispose. Se você executar o FxCop em seu código, ele será sinalizado como um aviso.
fonte
Você não vazará nada - pelo menos na implementação atual.
Chamar Dispose não limpará a memória usada pelo MemoryStream mais rápido. Ele vai parar seu fluxo de ser viável para chamadas de leitura / gravação após a chamada, o que pode ou não ser útil.
Se você tem certeza absoluta de que nunca deseja mover de um MemoryStream para outro tipo de fluxo, não fará nenhum mal se não chamar Dispose. No entanto, é geralmente uma boa prática em parte porque se você nunca fazer a mudança de usar um fluxo diferente, você não quer ser mordido por um bug difícil de encontrar, porque você escolheu o caminho mais fácil no início. (Por outro lado, há o argumento YAGNI ...)
A outra razão para fazer isso de qualquer maneira é que uma nova implementação pode introduzir recursos que seriam liberados no Dispose.
fonte
IDisposable
é um caso especial que vai contra as melhores práticas normais, você pode argumentar que é esse caso que você não deve fazer até que realmente precise, sob o YAGNI princípio.Sim, há um vazamento , dependendo de como você define LEAK e quanto DEPOIS você quer dizer ...
Se por vazamento você quer dizer "a memória permanece alocada, indisponível para uso, mesmo que você termine de usá-la" e por último você quer dizer a qualquer momento após chamar dispose, então sim, pode haver um vazamento, embora não seja permanente (ou seja, para a vida útil do tempo de execução de seus aplicativos).
Para liberar a memória gerenciada usada pelo MemoryStream, você precisa cancelar a referência, anulando sua referência a ela, para que se torne elegível para a coleta de lixo imediatamente. Se você não conseguir fazer isso, criará um vazamento temporário a partir do momento em que terminar de usá-lo, até que sua referência saia do escopo, porque nesse ínterim a memória não estará disponível para alocação.
O benefício da instrução using (em vez de simplesmente chamar dispose) é que você pode DECLARAR sua referência na instrução using. Quando a instrução using termina, não apenas dispose é chamado, mas sua referência sai do escopo, efetivamente anulando a referência e tornando seu objeto elegível para a coleta de lixo imediatamente sem exigir que você se lembre de escrever o código "reference = null".
Embora deixar de cancelar a referência de algo imediatamente não seja um vazamento de memória "permanente" clássico, definitivamente tem o mesmo efeito. Por exemplo, se você mantiver sua referência ao MemoryStream (mesmo após chamar dispose), e um pouco mais abaixo em seu método, você tenta alocar mais memória ... a memória em uso por seu fluxo de memória ainda referenciado não estará disponível para você até que você anule a referência ou saia do escopo, mesmo que você tenha chamado dispose e tenha terminado de usá-la.
fonte
Não é necessário chamar
.Dispose()
(ou agrupar comUsing
).O motivo de você ligar
.Dispose()
é para liberar o recurso o mais rápido possível .Pense em termos de, digamos, o servidor Stack Overflow, onde temos um conjunto limitado de memória e milhares de solicitações chegando. Não queremos esperar pela coleta de lixo programada, queremos liberar essa memória o mais rápido possível para que esteja disponível para novas solicitações de entrada.
fonte
FileStream
objetos e outro diferente paraMemoryStream
objetos?Isso já foi respondido, mas vou apenas acrescentar que o bom e antigo princípio da ocultação de informações significa que você pode, em algum momento futuro, querer refatorar:
para:
Isso enfatiza que os chamadores não devem se preocupar com o tipo de fluxo que está sendo retornado e torna possível alterar a implementação interna (por exemplo, ao fazer simulações para testes de unidade).
Você terá problemas se não tiver usado Dispose na implementação de sua barra:
fonte
Todos os streams implementam IDisposable. Envolva seu fluxo de memória em uma declaração de uso e você ficará bem e elegante. O bloco de uso garantirá que seu stream seja fechado e descartado, não importa o quê.
onde quer que você chame Foo, você pode fazer usando (MemoryStream ms = foo ()) e eu acho que você ainda deve estar bem.
fonte
Você não perderá memória, mas seu revisor de código está correto ao indicar que você deve fechar o fluxo. É educado fazer isso.
A única situação em que você pode perder memória é quando acidentalmente deixa uma referência ao fluxo e nunca o fecha. Você ainda não está realmente perdendo memória, mas está estendendo desnecessariamente a quantidade de tempo que afirma estar usando.
fonte
Eu recomendaria envolver o MemoryStream
bar()
em umausing
instrução, principalmente para consistência:.Dispose()
, mas é possível que em algum momento no futuro isso possa acontecer, ou você (ou outra pessoa em sua empresa) pode substituí-lo por seu próprio MemoryStream personalizado que o faz, etc.Outra coisa que geralmente faço em casos como
foo()
ao criar e retornar um IDisposable é garantir que qualquer falha entre a construção do objeto e oreturn
seja capturada por uma exceção, descarta o objeto e relança a exceção:fonte
Se um objeto implementa IDisposable, você deve chamar o método .Dispose quando terminar.
Em alguns objetos, Dispose significa o mesmo que Close e vice-versa, nesse caso, qualquer um é bom.
Agora, para sua pergunta particular, não, você não vai vazar memória.
fonte
Não sou especialista em .net, mas talvez o problema aqui sejam os recursos, ou seja, o identificador de arquivo, e não a memória. Acho que o coletor de lixo irá eventualmente liberar o fluxo e fechar o identificador, mas acho que sempre seria uma prática recomendada fechá-lo explicitamente, para garantir que o conteúdo seja descarregado no disco.
fonte
O descarte de recursos não gerenciados é não determinístico em linguagens com coleta de lixo. Mesmo se você chamar Dispose explicitamente, não terá absolutamente nenhum controle sobre quando a memória auxiliar será realmente liberada. Dispose é implicitamente chamado quando um objeto sai do escopo, seja saindo de uma instrução using ou exibindo a pilha de chamadas de um método subordinado. Dito isso, às vezes o objeto pode realmente ser um invólucro para um recurso gerenciado (por exemplo, arquivo). É por isso que é uma boa prática fechar explicitamente as instruções finally ou usar a instrução using. Felicidades
fonte
MemorySteram nada mais é que uma matriz de bytes, que é um objeto gerenciado. Esqueça de descartar ou fechar isso não tem nenhum efeito colateral além do custo da finalização.
Basta verificar o constutor ou o método de descarga de MemoryStream no refletor e ficará claro por que você não precisa se preocupar em fechá-lo ou descartá-lo, a não ser apenas para seguir as boas práticas.
fonte