Fugas de memória
6 answers
Em C#, estas são algumas fugas de memória comuns:
- não remover os ouvintes de eventos. Qualquer ouvinte de eventos que seja criado com um método anônimo ou expressão lambda que referencie um objeto externo irá manter esses objetos vivo. Lembre-se de remover os ouvintes de eventos quando eles já não são usados.
- manter as ligações de bases de dados ou os conjuntos de resultados abertos quando não são utilizados. Lembre-se de ligar para todos os objectos {[[1]}. utilize a Declaração
using
. - ligue para as funções C usando o p/invoque que atribui a memória que nunca irá libertar.
new
sem um delete
correspondente. Em C, significou uma chamada para alloc()
/malloc()
sem um free()
correspondente.
In. net, you don't get memory leaks in the traditional sense, because you are not supposed to release memory yourself. Em vez disso, você confia no coletor de lixo para liberá-lo para você. No entanto, isto não significa que nunca perderás a memória. Há várias maneiras que você pode acidentalmente manter uma referência ao redor que impede o coletor de lixo de fazer o seu trabalho. Estes incluem variáveis globais (especialmente listas, dicionários, e outros tipos de coleção que podem ser usados para "cache" objetos), manipuladores de eventos que se agarram à memória, referências recursivas de história, e o grande heap objeto.
É importante também notar aqui que só porque você vê um padrão de aumento do uso de memória em .Net, não significa necessariamente que a sua aplicação esteja a perder memória. Em casos de baixa pressão de memória geral, o coletor de lixo poderia simplesmente estar optando por economizar tempo, não coletando ainda, ou coletando dentro do espaço de endereçamento existente do processo apenas sem retornar a memória para o sistema operacional.
Uma boa leitura é Toda a gente pensa na recolha do lixo da forma errada.
Em geral, uma fuga de memória, ou qualquer fuga de recursos, é sempre que o programa aloca a memória (ou qualquer outro recurso) e, em seguida, omite para desacoplar quando terminar com ela. No vazamento de memória de aplicação nativa é o vazamento de recurso mais comum e pode acontecer quando a referência de recurso (o ponteiro para o bloco alocado) sai do escopo e é destruído, mas alocado recurso (a memória block) não é destruído. Neste caso, o recurso (memória) é vazado porque o programa perdeu a capacidade de liberá-lo, mesmo se ele quiser, porque ele já não se lembra da localização do recurso (o endereço do bloco).
Em aplicações controladas, as fugas de memória são um pouco mais complicadas. Uma vez que o tempo de execução pode rastrear referências a recursos automaticamente, ele também pode entender quando um recurso (um objeto) não é mais referenciado por qualquer parte ativa da aplicação (há nenhuma cadeia de referências de uma estrutura de pilha para esse recurso em qualquer thread) e assim o tempo de execução pode entender quando é seguro coletar os objetos não mais referências pela aplicação. Então, no mundo gerenciado, uma 'fuga' ocorreria quando você acredita que o aplicaiton não mais referencia um objeto (e assim ele pode ser coletado pelo tempo de execução), mas de fato, através de alguma cadeia de referências, você tem uma referência a ele e, portanto, ele não pode ser coletado. Eu recomendo O artigo de Raymond Chen ligado acima, é muito esclarecedor.Quando a memória é atribuída a uma aplicação, a aplicação tem a obrigação de devolver essa memória ao sistema operativo para que possa ser reutilizada por outras aplicações. Uma fuga de memória ocorre quando uma aplicação não libera essa memória, impedindo-a de ser realocada.
Para o código gerido, o coletor de lixo rastreia referências aos objetos criados por uma aplicação. Para a maioria das situações o CLR irá lidar com a alocação de memória e deallocation transparente e de forma razoável em nome do processo em curso. No entanto, os desenvolvedores do. NET ainda precisam considerar a gestão de recursos como ainda existem situações em que a memória pode vazar, apesar do trabalho do coletor de lixo.Considere o seguinte código:
Widget widget = new Widget();
A linha de código acima cria uma nova instância da classe do elemento gráfico e ao campo do elemento é atribuída uma referência a esse objecto. O GC acompanha as referências associadas a cada objecto e desalocata a memória de objetos para os quais não há referências fortes.
Vale a pena mencionar que a coleta de lixo da CLR só coletará objetos gerenciados, o código. NET pode e faz uso com frequência de recursos não geridos que não podem ser coletados automaticamente. As fugas de recursos não geridas ocorrem quando o objecto para o qual esses recursos foram afectados não consegue deslocá-los correctamente antes de a última referência a esses recursos sair do seu âmbito de aplicação, que deixa os recursos alocados, mas não referenciados e, portanto, inutilizável para a aplicação. ([8]) As Classes que referem directamente recursos não geridos devem assegurar que esses recursos sejam correctamente atribuídos. Um exemplo de fazer isso seria algo parecido com isto:public void ManagedObject : IDisposable
{
//A handle to some native resource.
int* handle;
public ManagedObject()
{
//AllocateHandle is a native method called via P/Invoke.
handle = AllocateHandle();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
//deal with managed resources here
FreeHandle(handle);
}
}
~ManagedType()
{
Dispose(false);
}
}
O parâmetro disposing
é falso quando é chamado de um finalizador. Isto é para evitar que os recursos gerenciados sejam usados dentro do finalizador, já que as referências gerenciadas devem ser consideradas inválidas nessa fase.
Note também que o método Dispose()
chama GC.SuppressFinalize(this)
o que impede que o finalizador corra para essa instância. Isto é feito porque os recursos que teriam sido desallocados no finalizador foram desallocados na chamada de eliminação fazendo uma invocação do fializador desnecessária.
Código do Cliente que faz uso de classes que lidam com recursos não gerenciados (ou qualquer classe que implementa IDisposable), deverá fazê-lo dentro de um using
bloco, para garantir que o IDisposable.Dispose
é chamado quando o acesso ao recurso não é mais necessário, pois isso irá cuidar tanto de recursos gerenciados e não gerenciados e, no caso do exemplo acima, garantir que uma chamada muito cara para o finalizador não é feita.
" fuga de memória "deve ser definida como" memória que é usada quando você acredita que não deve ser usada " para aplicar ao lixo coletado linguagens/períodos de execução como C#/Java.
Tradicionalmente "fuga de memória" é definida como uma memória que não está devidamente desalocada (ver link da Wikipédia em outras respostas), o que geralmente não acontece para ambientes coletados de lixo. Note que, devido a problemas com o tempo de execução, mesmo as linguagens coletadas de lixo podem vazar memória-ou seja, mesmo se JavaScript é lixo linguagem coletada, foi fácil de vazar grande quantidade de objetos JavaScript no tempo de execução JavaScript do Internet Explorer.