O que você precisa saber primeiro
1. Os programadores C/C++ gerenciam a memória sozinhos, enquanto a memória Java é automaticamente recuperada pelo GC.
Embora eu não esteja muito familiarizado com C++, provavelmente não cometi um erro de bom senso nisso.
2. O que é um vazamento de memória?
Um vazamento de memória refere-se à existência de memória no sistema que não pode ser reciclada, às vezes causando memória insuficiente ou falha do sistema.
Em C/C++, vazamentos de memória ocorrem quando a memória alocada não é liberada.
3. Há um vazamento de memória em Java. Devemos admitir isso antes de continuarmos a discuti-lo. Embora Java tenha vazamentos de memória, você basicamente não precisa se preocupar com isso, especialmente aqueles que não são específicos sobre o código em si.
Vazamentos de memória em Java certamente significam: existem objetos inúteis que não podem ser reciclados pelo coletor de lixo.
E mesmo que haja um problema de vazamento de memória, ele pode não aparecer.
4. Os parâmetros em Java são todos passados por valor.
Basicamente não há objeção aos tipos básicos, mas não podemos ter nenhuma objeção aos tipos de referência.
Vazamentos de memória Java
1. Estouro de memória heap (outOfMemoryError: espaço heap java)
Na especificação JVM, a memória no heap é usada para gerar instâncias de objetos e matrizes.
Se subdividida, a memória heap também pode ser dividida em geração jovem e geração antiga. A geração jovem inclui uma área do Éden e duas áreas de sobrevivência.
Quando um novo objeto é gerado, o processo de aplicação de memória é o seguinte:
a. A jvm primeiro tenta alocar a memória necessária para o novo objeto na área eden;
b. Se o tamanho da memória for suficiente, o aplicativo termina, caso contrário, o próximo passo é;
c.JVM inicia o youngGC e tenta liberar objetos inativos na área Eden. Após a liberação, se o espaço Eden ainda não for suficiente para colocar novos objetos, ela tenta colocar alguns dos objetos ativos no Eden na área Survivor;
d. A área Survivor é usada como área de troca intermediária entre o Éden e o antigo. Quando a área ANTIGO tiver espaço suficiente, os objetos na área Sobrevivente serão movidos para a área Antigo, caso contrário serão retidos na área Sobrevivente;
e. Quando não houver espaço suficiente na área OLD, a JVM realizará GC completo na área OLD;
f. Após o GC completo, se as áreas Survivor e OLD ainda não conseguirem armazenar alguns objetos copiados do Eden, fazendo com que a JVM não consiga criar uma área de memória para novos objetos na área Eden, um "erro de falta de memória" aparecerá:
outOfMemoryError: espaço de heap java
2. Estouro de memória na área do método (outOfMemoryError: espaço permgem)
Na especificação JVM, a área de método armazena principalmente informações de classe, constantes, variáveis estáticas, etc.
Portanto, se o programa carregar muitas classes ou usar tecnologia de geração de proxy dinâmico, como reflexão ou gclib, poderá causar um estouro de memória nesta área. Geralmente, a mensagem de erro quando ocorre um estouro de memória nesta área é:
outOfMemoryError: espaço permitido
3. Estouro de pilha de threads (java.lang.StackOverflowError)
A pilha de threads é uma estrutura de memória exclusiva do thread, portanto, problemas com a pilha de threads devem ser erros gerados quando um thread está em execução.
Geralmente, o estouro da pilha de threads é causado por recursão muito profunda ou por muitos níveis de chamadas de método.
A mensagem de erro quando ocorre um estouro de pilha é:
Java. longo. Erro StackOverflow
Vários cenários de vazamentos de memória:
1. Objetos de vida longa contêm referências a objetos de vida curta.
Este é o cenário mais comum de vazamentos de memória e um problema comum no design de código.
Por exemplo: se variáveis locais forem armazenadas em cache em um mapa estático global e não houver operação de limpeza, o mapa ficará cada vez maior com o tempo, causando vazamentos de memória.
2. Modifique o valor do parâmetro do objeto no hashset, e o parâmetro é o campo usado para calcular o valor do hash.
Depois que um objeto é armazenado na coleção HashSet, os campos do objeto que participam do cálculo do valor hash não podem ser modificados, caso contrário, o valor hash modificado do objeto será diferente do valor hash quando foi originalmente armazenado na coleção HashSet , neste caso, mesmo que o método contains use a referência atual do objeto como parâmetro para recuperar o objeto da coleção HashSet, ele retornará o resultado de que o objeto não pode ser encontrado, o que também resultará na falha em encontrá-lo. exclua o objeto atual da coleção HashSet, causando vazamento de memória.
3. Defina o número de conexões e tempo de desligamento da máquina
Abrir uma conexão que consome muitos recursos por um longo período também pode causar vazamentos de memória.
Vejamos um exemplo de vazamento de memória:
public class Stack { private Object[] elementos=new Object[10]; public void push(Object e){ garantaCapacity(); tamanho == 0) lançar new EmptyStackException(); retornar elementos[--size] } private void garantirCapacity(){ if(elements.length == size){ Object[] oldElements = elementos; = novo Objeto[2 * elementos. comprimento+1]; Sistema. arraycopy(oldElements,0, elementos, 0, tamanho);
O princípio acima deve ser muito simples. Se 10 elementos forem adicionados à pilha e todos forem retirados, embora a pilha esteja vazia e não haja nada que queiramos, este objeto não pode ser reciclado. Condição: Inútil, não pode ser reciclado.
Mas mesmo a existência de tal coisa pode não levar necessariamente a quaisquer consequências. Se esta pilha for menos utilizada,
É apenas um desperdício de alguns K de memória. De qualquer forma, nossa memória já está até G, então que impacto isso terá? Além disso, essa coisa será reciclada em breve, então o que isso importa? Vejamos dois exemplos abaixo.
Exemplo 1
classe pública Ruim{ public static Stack s=Stack(); push(novo Objeto()); pop(); //Há um vazamento de memória em um objeto aqui. push(new Object()); //O objeto acima pode ser reciclado, o que equivale à autocura}}
Por ser estático, existirá até o encerramento do programa, mas também podemos ver que possui uma função de autocura.
Ou seja, se sua pilha tiver no máximo 100 objetos, apenas 100 objetos não poderão ser reciclados. Na verdade, isso deve ser fácil de entender. A pilha contém 100 referências internamente. , porque assim que colocarmos novos progressos, as referências anteriores desaparecerão naturalmente!
Exemplo 2
classe pública NotTooBad{ public void doSomething(){ Stack s=new Stack() s. push(new Object()); //outros códigos. pop();//Isso também faz com que o objeto não possa ser reciclado e com vazamento de memória. } // Sai do método, s é automaticamente inválido, s pode ser reciclado e as referências dentro da pilha desaparecem naturalmente, então // A autocura também pode ser feita aqui, e pode-se dizer que este método não tem um problema de vazamento de memória, mas será entregue posteriormente // Só é entregue ao GC, porque está fechado e não aberto para o mundo exterior. Código 99.9999% das // situações não terão nenhum impacto. É claro que se você escrever esse código, ele não terá nenhum efeito negativo, mas // definitivamente pode ser considerado um código lixo. Vou adicionar um nele. Um loop for vazio não terá grande impacto, certo?
Os dois exemplos acima são triviais, mas vazamentos de memória em C/C++ não são ruins, mas piores.
Se eles não forem reciclados em um só lugar, eles nunca poderão ser reciclados. Se você chamar esse método com frequência, a memória será consumida!
Como o Java também tem uma função de autocura (eu mesmo a nomeei e ainda não solicitei uma patente), o problema de vazamento de memória do Java pode ser quase ignorado, mas aqueles que o conhecem não devem cometê-lo.
Para evitar vazamentos de memória, você pode consultar as seguintes sugestões ao escrever código:
1. Libere referências a objetos inúteis o mais cedo possível;
2. Use processamento de string, evite usar String e use StringBuffer extensivamente. Cada objeto String deve ocupar uma área independente de memória;
3. Use variáveis estáticas o mínimo possível, pois as variáveis estáticas são armazenadas na geração permanente (área de métodos), e a geração permanente basicamente não participa da coleta de lixo;
4. Evite criar objetos em loops;
5. Abrir arquivos grandes ou extrair muitos dados do banco de dados de uma vez pode facilmente causar estouro de memória, portanto, nesses locais, você deve calcular aproximadamente a quantidade máxima de dados e definir os valores mínimo e máximo de espaço de memória necessários.