Problema com Thread e leak de conexão

Bom dia,

pessoal espero conseguir apoio com vocês, vou tentar detalhar bem para vocês.

Faz algum tempo que estou trabalhando em um sistema onde tem muitas Threads e numero de conexões com o banco muito grande.

Consegui amenizar o problema de conexões achando em raros pontos no código que utiliza jdbc puro e que fechava a Connection no try
ao invés do finally mas confesso que foi em apenas uns 2 ou 3 métodos, surtiu efeito mas como imaginei muito pouco melhorou.

O sistema é grande e temos hibernate e jdbc trabalhando juntos, imagino também que cerca de umas 30 threads rodam ao mesmo tempo,
como trabalhamos em alguns casos com pool de threads não da de saber exatamente quanto está rodando sempre.

O problema de conexão coloquei o c3p0 e o leak realmente acabou mas ele não aguenta o pique do sistema, simplesmente fica muito lento
chegando a travar em menos de 10 minutos da aplicação rodando em produção. Então continua o tomcat-dbcp.jar, atualizei para ver
se conseguia alguma melhoria.

Os sqls são executados com o jdbcTemplate e hibernateTemplate do spring que controla o fechamento da conexão e etc. Em raros lugares
é que utilizo um PreparedStatement e um ResultSet.

O problema que estou tendo com thread é o seguinte, tenho espaço em memória, utilizo a visulavm para monitoramento, mas quando a thread
vai ser iniciada ele acusa um outOfMemory mesmo a JVM ainda tendo 1 giga de memória livre.

Se puderem ajudar fico agradecido.

Estou com o mesmo problema aqui. Não importa o quanto você aumente o heap.
No meu caso, vi que o problema são BufferedImages. O coletor de lixo não está resolvendo algumas referências. Então passei null para algumas, e meu profile melhorou em muito, mas ainda assim, depois de 12hs, o software estoura o heap.
Estou em uma pesquisa para ver como posso resolver esses problemas.




E ai Julio vejo que não sou o único com problema.
O que mais me preocupa é que no meu caso o uso de memória fica establizado, a JVM vai utilizando e quando roda o GC full
ele baixa tudo e vai aos poucos alocando utilizando e fica nesse ciclo.

A questão é como eu tenho um Giga livre (meu xms é de 3 giga e o xmx de 3,5).

É muita me mória ele no momento que estava dando erro estava utilizando apenas 2 giga e mesmo assim reclamou
de outOfMemory.

Como descobriu esse problema com BufferedImages???

Descobri pela análise dos objetos alocados. Esse software não pode parar de rodar por nada. Tem que estar firme 24hs por dia.
A quantidade de bytes alocados revela Imagens digitais, fora o protocolo de comunicação.

Estou tendo mais trabalho de otimizar isso aqui, com coletor de lixo, do que se fosse gerenciar memória manualmente com c++.


[quote=regisbten]E ai Julio vejo que não sou o único com problema.
O que mais me preocupa é que no meu caso o uso de memória fica establizado, a JVM vai utilizando e quando roda o GC full
ele baixa tudo e vai aos poucos alocando utilizando e fica nesse ciclo.

A questão é como eu tenho um Giga livre (meu xms é de 3 giga e o xmx de 3,5).

É muita me mória ele no momento que estava dando erro estava utilizando apenas 2 giga e mesmo assim reclamou
de outOfMemory.

Como descobriu esse problema com BufferedImages???[/quote]

Você está usando um SO de 32 bits ou de 64 bits? Se estiver usando um SO de 64 bits, está usando um JDK de 64 bits?
É que o maior valor para -Xmx em 32 bits é cerca de 1,6 GB, mesmo que você especificar mais que isso.

Julio, remotamente não consigu executar o heap dump que da essa
quantidade de objetos, somente local. Você consegui fazer isso remotamente?

entanglement no server está com o centOS 64 bits, realmente a JDK é 32 bits, mas pelo
que tenho monitorado ele utiliza mais do que 2 giga, através de monitoramento
da de acomapanhar a utilização se não me engano na época quando entrei eles
acharam esse teto de 3,5 giga.

Pessoal sempre bom a troca de info. Julio to no aguardo da sua resposta.

Só como exemplo, estou monitorando, acabou de rodar o GC full.


[quote=juliocbq]Descobri pela análise dos objetos alocados. Esse software não pode parar de rodar por nada. Tem que estar firme 24hs por dia.
A quantidade de bytes alocados revela Imagens digitais, fora o protocolo de comunicação.

Estou tendo mais trabalho de otimizar isso aqui, com coletor de lixo, do que se fosse gerenciar memória manualmente com c++. [/quote]

Seu profiler está acusando leak em char[]. Isso é tipicamente alocado em strings, não em BufferedImages. Você tem certeza que seu leak é nas BufferedImages?

Uma boa é usar o profiler do Netbeans. Ele tem a opção para rastrear quem fez a alocação do que. Aí vc pode descobrir se são mesmo as bufferedimages que dão problema (regis, essa dica também vale para vc).

Note que vc pode ter o leak em outro lugar, e o bufferedimage estourar o outofmemory só pq gera um pico de alocação de memória.

[quote=ViniGodoy][quote=juliocbq]Descobri pela análise dos objetos alocados. Esse software não pode parar de rodar por nada. Tem que estar firme 24hs por dia.
A quantidade de bytes alocados revela Imagens digitais, fora o protocolo de comunicação.

Estou tendo mais trabalho de otimizar isso aqui, com coletor de lixo, do que se fosse gerenciar memória manualmente com c++. [/quote]

Seu profiler está acusando leak em char[]. Isso é tipicamente alocado em strings, não em BufferedImages. Você tem certeza que seu leak é nas BufferedImages?

Uma boa é usar o profiler do Netbeans. Ele tem a opção para rastrear quem fez a alocação do que. Aí vc pode descobrir se são mesmo as bufferedimages que dão problema (regis, essa dica também vale para vc).

Note que vc pode ter o leak em outro lugar, e o bufferedimage estourar o outofmemory só pq gera um pico de alocação de memória.[/quote]
Parece que resolvi o problema vini. Existia uma lista circular que envolvia as imagens. Lembra que te disse que usava o algoritmo base64 para codifica-la, guarda-las em disco, num string?

[code]byte b[] = Base64.decode(lstLogAcesso.get(0).getUsuario().getFoto());//Olha aqui a lista “lstLogAcesso”
InputStream in = new ByteArrayInputStream(b);

                // Image img = Toolkit.getDefaultToolkit().createImage(b);
                BufferedImage img = null;
                try {
                    img = ImageIO.read(in);
                } catch (IOException ex) {
                    Logger.getLogger(UltimoAcessoPanel.class.getName()).log(Level.SEVERE, null, ex);
                }
                Image rsz = img.getScaledInstance(114, 158, 0);
                ImageIcon imgIcon = new ImageIcon(rsz);

                lbFotografia.setIcon(imgIcon);
                img.flush();
                img = null;
                rsz.flush();
                rsz = null;
                try {
                    in.close();
                } catch (IOException ex) {
                    Logger.getLogger(UltimoAcessoPanel.class.getName()).log(Level.SEVERE, null, ex);
                }
                b = null;
                imgIcon = null;[/code]

Passei a controlar a lista, e as imagens foram dealocadas.

Resultado:


Foi importante passar null para as referências nas imagens. Conforme o gráfico, o GC passou a trabalhar menos, e de forma mais eficiente.

Essas ferramentas citadas pelo vini são ótimas(obrigado pelo esclarecimento).

Provavelmente o leak estava na lista, então.

É muito comum o leak não estar onde o OutOfMemoryError ocorre. Especialmente os leaks que só ocorrem depois de muito tempo.

Isso pq o sistema tem picos, e são nesses picos que eles estouram. A classe de leak, quando o leak demora, pode ser uma que aloca poucos bytes, e vai enxendo a memória aos poucos.

Aí, qualquer pico em outro lugar que ocorra, vai acusar o OutOfMemoryError…

É pela existencia de ferramentas assim que defendo que é mais fácil gerar código java mais eficiente que código C ou C++ hoje em dia. Sabe quantas eras geológicas você levaria para achar esse erro sem um profiler como esse??

Foi como comentei em outro tópico. Se o problema de performance se resumisse apenas a velocidade do código nativo gerado pelo compilador, estaríamos em ótimos lençóis… hehehheheh

[quote=regisbten]Julio, remotamente não consigu executar o heap dump que da essa
quantidade de objetos, somente local. Você consegui fazer isso remotamente?

entanglement no server está com o centOS 64 bits, realmente a JDK é 32 bits, mas pelo
que tenho monitorado ele utiliza mais do que 2 giga, através de monitoramento
da de acomapanhar a utilização se não me engano na época quando entrei eles
acharam esse teto de 3,5 giga.

Pessoal sempre bom a troca de info. Julio to no aguardo da sua resposta. [/quote]

Eu estou executando localmente o profiler. É uma aplicação desktop aqui. Você não consegue dar um attach pelo netbeans?

[quote=ViniGodoy]Provavelmente o leak estava na lista, então.

É muito comum o leak não estar onde o OutOfMemoryError ocorre. Especialmente os leaks que só ocorrem depois de muito tempo.

Isso pq o sistema tem picos, e são nesses picos que eles estouram. A classe de leak, quando o leak demora, pode ser uma que aloca poucos bytes, e vai enxendo a memória aos poucos.

Aí, qualquer pico em outro lugar que ocorra, vai acusar o OutOfMemoryError…[/quote]

Sim, com pouco espaço no heap, qualquer instrução que gerasse um pico iria estourá-lo. Então não tem nenhuma validade o stacktrace.

É pela existencia de ferramentas assim que defendo que é mais fácil gerar código java mais eficiente que código C ou C++ hoje em dia. Sabe quantas eras geológicas você levaria para achar esse erro sem um profiler como esse??

Foi como comentei em outro tópico. Se o problema de performance se resumisse apenas a velocidade do código nativo gerado pelo compilador, estaríamos em ótimos lençóis… hehehheheh[/quote]

O QT e o VisualStudio possuem ferramentas que detectam leaks, mas não com gráficos e precisão dessa maneira. Estou começando a pensar da mesma maneira que você.
O profiler me poupou um dia ou mais de trabalho.

Pois é. E isso se vc usar essas APIs. A maioria dos profilers do C e do C++ são intrusivos. Exigem que você tenha programado explicitamente para ele. O que é um inferno quando você tem dlls de terceiros no seu código.

Algumas ferramentas menos intrusivas envolvem recompilação do código, numa plataforma deles. O que também é longe de ser o ideal, já que as vezes a ferramente não tem o suporte que seu compilador nativo padrão (a que tentamos, por exemplo, reclamava de algumas templates de uma biblioteca de xml, que usávamos com a boost).

Agora, no Java, você não só tem esses profilers fantásticos, como eles ainda são de graça. E inclui testes de memória e velocidade. Achei um similar para .net chamado DotTrace, mas vai lá ver o preço da licencinha dele…

Ninguém tem problema ocm leak de conexão?

Tem que olhar no profiler, e ver qual objeto está consumindo mais memória. Posta a análise dos objetos para olharmos.

[quote=ViniGodoy]Pois é. E isso se vc usar essas APIs. A maioria dos profilers do C e do C++ são intrusivos. Exigem que você tenha programado explicitamente para ele. O que é um inferno quando você tem dlls de terceiros no seu código.

Algumas ferramentas menos intrusivas envolvem recompilação do código, numa plataforma deles. O que também é longe de ser o ideal, já que as vezes a ferramente não tem o suporte que seu compilador nativo padrão (a que tentamos, por exemplo, reclamava de algumas templates de uma biblioteca de xml, que usávamos com a boost).

Agora, no Java, você não só tem esses profilers fantásticos, como eles ainda são de graça. E inclui testes de memória e velocidade. Achei um similar para .net chamado DotTrace, mas vai lá ver o preço da licencinha dele…[/quote]

O preço tá quase 1 barão.
R$898

Ja estou trazendo para ca o heap dump para postar aqui,
li pesquisando que esse é um problema do DBCP mesmo, em
quando trabalha no limite, e se perde no pool e fica
algumas conexões “zumbis”, como dize ja tentei c3p0 e o mesmo
não aguenta a carga.

Ja setei o removeAbandoned para true e mais algumas configurações
porém nada resolveu.

Daqui a pouco o dump ja deve estar aqui e posto.