Como encontrar uma fuga de memória Java

como você encontra uma fuga de memória em Java (usando, por exemplo, JHat)? Tentei carregar o monte de lixo em JHat para dar uma olhada básica. No entanto, eu não entendo como é suposto eu ser capaz de encontrar a referência raiz (ref) ou o que quer que seja chamado. Basicamente, eu posso dizer que existem várias centenas de megabytes de entradas de tabela de hash ([java.util.HashMap$Entry ou algo do género), mas os mapas são usados por todo o lado... Existe alguma maneira de procurar por mapas grandes, ou talvez encontrar raízes gerais de grandes árvores de objectos?

[editar] Ok, eu li as respostas até agora, mas vamos apenas dizer que eu sou um bastardo barato (o que significa que eu estou mais interessado em aprender a usar JHat do que para pagar por JProfiler). Além disso, JHat está sempre disponível, uma vez que faz parte do JDK. A não ser, claro, que o JHat só tenha força bruta, mas não acredito que possa ser esse o caso.

além disso, acho que não vou ser capaz de modificar realmente (adicionando o registo de todos os tamanhos de mapas) e passa o tempo suficiente para eu reparar na fuga.

Author: Community, 2008-09-02

9 answers

USO a seguinte abordagem para encontrar fugas de memória em Java. Eu usei o jProfiler com grande sucesso, mas eu acredito que qualquer ferramenta especializada com capacidades de grafagem (diffs são mais fáceis de analisar em forma gráfica) funcionará.

  1. Inicie a aplicação e espere até chegar ao estado "estável", quando toda a inicialização estiver completa e a aplicação estiver inactiva.
  2. executar a operação suspeita de produzir uma fuga de memória várias vezes para permitir qualquer cache, relacionado com DB inicialização a ter lugar.
  3. Passa o GC e tira uma fotografia da memória. Volte a executar a operação. Dependendo da complexidade da operação e do tamanho dos dados que são processados operação pode precisar ser executado várias a muitas vezes. Passa o GC e tira uma fotografia da memória. Faz uma pesquisa para duas fotos e analisa-as.

Basicamente, a análise deve começar a partir da maior diferença positiva por, digamos, tipos de objectos e descobrir o que faz com que esses objectos extra se colem memoria.

Para aplicações web que processam pedidos em várias threads a análise torna-se mais complicada, mas mesmo assim a abordagem geral ainda se aplica.

Fiz uma série de projectos especificamente destinados a reduzir a pegada de memória das aplicações e esta abordagem geral, com alguns ajustes e truques específicos das aplicações, funcionou sempre bem.
 118
Author: Dima Malenko, 2008-09-02 18:49:35
Questionador aqui, eu tenho que dizer que obter uma ferramenta que não leva 5 minutos para responder a qualquer Clique torna muito mais fácil encontrar potenciais vazamentos de memória.

, uma vez que as pessoas estão sugerindo várias ferramentas ( só testei o visual do wm desde que eu tenho de que o JDK e JProbe julgamento ) eu pensei que eu deveria sugerir um livre / open source ferramenta construída sobre a plataforma Eclipse, o Analisador de Memória (por vezes referido como o SAP analisador de memória) disponível em http://www.eclipse.org/mat/ .

O Que é realmente legal sobre esta ferramenta, é que ela indexado de informação de pilha quando, pela primeira vez aberto, o que permitiu isso para mostrar dados como mantidos pilha sem esperar 5 minutos para cada objeto (praticamente todas as operações foram muito mais rápido do que as outras ferramentas que eu tentei).

Quando você abrir o 'dump', o primeiro ecrã mostra-lhe um gráfico circular com os maiores objectos (contando o heap retido) e pode-se navegar rapidamente até aos objectos que são grandes para conforto. Ele também tem um achado provável vazar suspeitos que eu Recon pode ser útil, mas como a navegação foi suficiente para mim Eu não realmente entrar nele.

 47
Author: jwiklund, 2015-09-11 17:17:07
Uma ferramenta é uma grande ajuda.

No Entanto, há momentos em que você não pode usar uma ferramenta: o despejo de pilha é tão grande que falha a ferramenta, você está tentando solucionar problemas de uma máquina em algum ambiente de produção para o qual você só tem acesso a shell, etc.

Nesse caso, ajuda saber o caminho em torno do ficheiro de descarga hprof. Procurem SITES a começar. Isto mostra quais objetos estão usando mais memória. Mas os objetos não são agrupados apenas por Tipo: cada entrada também inclui uma identificação "trace". Você pode então procurar por esse "TRACE NNN" para ver os poucos quadros superiores da pilha onde o objeto foi alocado. Muitas vezes, uma vez que eu vejo onde o objeto é alocado, eu encontro um bug e estou pronto. Além disso, note que você pode controlar quantos frames são gravados na pilha com as opções para-Xrunhprof.

Se você verificar o site de alocação, e não ver nada de errado, você tem que começar a recuar de alguns desses objetos vivos para objetos de raiz, para encontrar o uma cadeia de referência inesperada. É aqui que uma ferramenta realmente ajuda, mas você pode fazer a mesma coisa à mão (bem, com grep). Não há apenas um objeto raiz (isto é, objeto não sujeito a coleta de lixo). Threads, classes, and stack frames act as root objects, and anything they reference strongly is not collectible.

Para fazer o encadeamento, procure na secção HEAP DUMP entradas com o ID de mau traço. Isto irá levá - lo a um item OBJ ou ARR, que mostra um identificador de objecto único em hexadecimal. Procure por todas as ocorrências desse id para encontrar quem tem uma forte referência ao objeto. Segue cada um desses caminhos para trás enquanto eles se ramificam até que descubras onde está a fuga. Vês porque é que uma ferramenta é tão útil?

Os membros estáticos são reincidentes por fugas de memória. De fato, mesmo sem uma ferramenta, valeria a pena passar alguns minutos olhando através de seu código para membros do mapa estático. Um mapa pode crescer? Alguma coisa limpa as entradas?
 12
Author: erickson, 2008-09-02 18:30:42

Na maioria das vezes, em aplicações empresariais o heap Java dado é maior do que o tamanho ideal de max 12 a 16 GB. Eu achei difícil fazer o perfil do NetBeans funcionar diretamente nesses aplicativos java grandes.

Mas normalmente isso não é necessário. Você pode usar o utilitário jmap que vem com o jdk para fazer um "live" heap dump , ou seja, o jmap irá dump o heap depois de correr o GC. Fazer alguma operação na aplicação, esperar até que a operação esteja concluída, em seguida, tomar outro" live " heap despejo. Use ferramentas como o Eclipse MAT para carregar os cabeçotes, Ordenar no histograma, ver quais objetos aumentaram, ou quais são os mais altos, isso daria uma pista.
su  proceeuser
/bin/jmap -dump:live,format=b,file=/tmp/2930javaheap.hrpof 2930(pid of process)

Só há um problema com esta abordagem; enormes depósitos de heap, mesmo com a opção ao vivo, podem ser demasiado grandes para serem transferidos para a volta de desenvolvimento, e podem precisar de uma máquina com memória/RAM suficiente para abrir.

É aí que surge o histograma da classe. Pode descarregar um histograma de classe ao vivo com a ferramenta jmap. Isto irá dar apenas o histograma de classe do uso da memória.Basicamente, não terá a informação para encadear a referência. Por exemplo, pode colocar o array char no topo. E a aula de cordas algures lá em baixo. Tens de ser tu a desenhar a ligação.
jdk/jdk1.6.0_38/bin/jmap -histo:live 60030 > /tmp/60030istolive1330.txt

Em vez de fazer dumps de dois heap, tome dois histogramas de classe, como descrito acima; em seguida, compare os histogramas de classe e veja as classes que estão aumentando. Veja se você pode relacionar as classes Java com suas classes de Aplicação. Presente vai dar uma boa pista. Aqui está um script pythons que pode ajudá-lo a comparar dois dumps de histograma jmap. histogramparser.py

Finalmente ferramentas como JConolse e VisualVm são essenciais para ver o crescimento da memória ao longo do tempo, e ver se há uma fuga de memória. Finalmente, às vezes o seu problema pode não ser uma fuga de memória , mas alta utilização de memória.Para isto, active o registo GC; use um GC mais avançado e novo compactador, como o G1GC; e você poderá usar ferramentas jdk como o jstat para ver o comportamento GC Vivo
jstat -gccause pid <optional time interval>

Outras referências ao google for-jhat, jmap, Full GC, Humongous allocation, G1GC

 7
Author: Alex Punnen, 2015-10-02 08:47:59
Existem ferramentas que devem ajudá-lo a encontrar o seu vazamento, como JProbe, YourKit, AD4J ou JRockit. O último é o que eu conheço melhor. Qualquer boa ferramenta deve deixá-lo perfurar até um nível onde você pode facilmente identificar quais vazamentos, e onde os objetos vazados são alocados.

Usar HashTables, Hashmaps ou similar é uma das poucas maneiras que você pode efetivamente vazar memória em Java. Se eu tivesse que encontrar a fuga à mão eu iria peridicamente imprimir o tamanho dos meus HashMaps, e a partir daí encontrar aquele onde eu adicionar itens e esquecer de apagá-los.

 5
Author: Tnilsson, 2008-09-02 17:48:30
Bem, há sempre a solução de baixa tecnologia de adicionar registro do tamanho de seus mapas quando você os modifica, em seguida, procure os registros para os quais os mapas estão crescendo além de um tamanho razoável.
 4
Author: Mike Stone, 2008-09-02 17:39:50
Precisas mesmo de usar um profiler de memória que rastreie as atribuições. Dê uma olhada em JProfiler - seu recurso" heap walker " é ótimo, e eles têm integração com todos os principais IDEs Java. Não é gratuito, mas também não é tão caro ($499 por uma única licença) - você vai queimar US $500 no valor de tempo muito rapidamente lutando para encontrar uma fuga com ferramentas menos sofisticadas.
 0
Author: McKenzieG1, 2008-09-02 17:46:46
O NetBeans tem um perfil embutido.
 0
Author: wbkang, 2008-09-02 18:30:34

Pode querer verificarjconsole . É também parte do JDK e eu achei útil encontrar vazamentos de memória / referência em conjunto com jhat. Dê também uma olhada em este item do blog.

 -1
Author: JMM, 2008-09-02 18:39:08