Liberar memória utilizada

Olá a todos…

Bom pessoal, percebi que minha aplicação estava ficando lerda após varios minutos de uso sem interrupção, entao eu fiz uma Thread pra monitorar e exibir na tela inicial quanto de memoria eu tinha alocado, quanto estava sendo usado e quanto estava livre, meu programa começa com ± 17764 Kb alocado, e usando ± 13500 à 14500 Kb na memoria, e percebi que cada vez que eu abro uma tela, e fecho, o espaço na memória que foi utilizado por ela nao é liberado. entao o que acontecia era que eu ia usando o programa até ele usar os 65088 Kb que é o total de memória que o meu programa pode usar, e entao a seguinte excessao era lançada:
[color=red]Exception occurred during event dispatching:
java.lang.OutOfMemoryError: Java heap space[/color]

Blz, até entao eu nao me preocupava com objetos, pq tinha o tal do garbage collector, só que nao tava liberando a memória, entao fui pesquisar, e encontrei nesse link algo bem simples mas que achei bastante util, http://imasters.uol.com.br/artigo/3148/ajudando_o_garbage_do_java, dai fiz um teste, sobreescrevi o metodo finalize(), atribui null a todos os objetos da minha tela, e ainda coloquei um System.out.println(“entrou no finalize”); só pra ter certeza de que seria executado, e o metodo finalize é executado sim, inclusive depois da terceira vez q eu abro a tela, ele é executado sempre que abro e fecho uma tela.

Mas mesmo fazendo isso, o espaço usado na memoria ainda nao esta sendo liberado. O menu do meu sistema é dinamico e funciona com reflexao, entao eu também criei uma Lista pra armazenar as telas que sao abertas, e quando eu fecho essa tela, eu atribuo null no objeto referente a ela, buscando a mesma nessa lista, e depois removo ela da lista, e chamo System.gc(); para pedir a maquina virtual que rode o garbage collector.

Alguem tem alguma ideia se esta faltando alguma coisa ??? Eu to fazendo algo de errado ???

Sei lah, eu penso que quando eu abro uma tela, td bem ela vai ocupar certo espaço na memoria, mas quando eu fecho ela, esse espaço deveria ser liberado, e isso nao acontece, agora o porque eu nao sei…

vou colocar um codigozinho do que eu fiz na tela de vendas:

aqui eu sobreescrevi o metodo finalize()

[code]protected void finalize() {
try {
//todos os objetos declarados da tela recebem null, inclusive os JLabel, JButton…

    System.out.println("-------------- entrou no finalize --------------");
} catch (Throwable ex) {
    ex.printStackTrace();
}

}[/code]

aqui no evendo windowClosed do form eu atribuo null na tela e removo ela daquela lista que mencionei (listaObjetos está declarado global na classe)

listaObjetos.removerObjeto(getClass().getName());

e aqui é o codigo que uso para criar a tela, e adicionar ela na lista, (é só a parte que interessa), onde “nome” é um parametro do nome da classe

Class classe = Class.forName(nome); Object obj = classe.newInstance(); listaObjetos.addObjeto(nome, obj);

e aqui é o método removerObjeto

public void removerObjeto(String nome) { for (int i = 0; i < lNomes.size(); i++) { String s = lNomes.get(i); if (s.equals(lNomes.get(i))) { lObjetos.set(i, null); lNomes.remove(i); lObjetos.remove(i); System.gc(); break; } } }

Desde já grato !!! t+

Olá cleiton herrmann,

Cara estive pensando na estratégia que adotou, e encontrei alguns pontos de melhoria.
Por exemplo:

Sobre finalizadores, no livro Java Effective escrito pela Sun, logo no primeiro capitulo ele fala sobre evitar finalizadores (uma desenvolvedora chamada Vanessa fez um resumo do livro em http://br.geocities.com/vanessasabino/java.html).
Outra é sobre a invocação da Garbage não e instantânea, como descrito em
http://doc.java.sun.com/DocWeb/api/java.lang.Runtime

Talvez para que a memória seja menos consumida, seria uma boa idéia pensar em criar uma fabrica de singletons dessas suas telas.

[]'s
JL

Olá Mero_Aprendiz…

intaum, nesse esquema de lista que eu usei, antes eu nao estava removendo as telas quando eu fechava, só que na maioria das telas, eu executo algumas coisas ja logo no construtor, e ficar trabalhando com uma unica instancia da tela, faria com que “essas coisas” nao sejam executadas na segunda, terceira vez que eu acessar a tela, entao eu comecei a remover a tela a lista tbem, além do que, vai dar muito trabalho alterar varias telas para executar “essas coisas” de outra forma…

nao é exatamente o padrao singleton, mas funciona igual, se o objeto ja esta na lista, ele nao cria, somente faz um setVisible(true) …

vou dar uma olhada no resumo da vanessa que vc mencionou…

quanto ao garbage nao ser executado logo que invocado, eu coloquei uma System.out no metodo finalize() pra ter certeza que ele era executado, e de fato o metodo finalize foi executado a mesma quantidade de vezes que eu abri a tela, agora o pq q a memoria usada nao foi liberada eu nao sei

to muito de cara com isso, pois se o finalize() é chamado pelo garbage collector, e deveria finalizar e liberar a memoria usada pelo objeto (que deve estar null), nao sei pq nao libera…

mais vlw as dicas ai, vou dar uma olhada, t+

se alguem tiver mais alguma sugestao, é bem vinda !!!

Olá cleiton herrmann…
Vamos dando andamento a essa conversa, acredito que ela vai ser muito proveitosa para todos.

Gostaria de fazer algumas perguntas:
Você está usando alguma ferramente da Profiling, para saber se a mémoria que é alocada é mesmo por objetos que são componentes das telas?
Essa sua aplicação é em Swing, AWT…?
Qual a versão da máquina virtual que está usando?

Opa blz, tbem acho que será proveitoso a todos…

Bom, respondendo as perguntas…

  • Quanto a usar uma ferramenta profiler pra saber os recursos usados pelo programa, eu nao estou usando nenhuma, somente estou usando os metodos da classe Runtime
    maxMemory(); (maximo de memoria que tenho pra usar)
    totalMemory(); (a quantia de memoria que esta alocada)
    freeMemory(); (a memoria que ainda esta livre para ser usada) e
    totalMemory() - freeMemory() (para saber a quantia de memória que esta sendo usada)

criei uma thread que fica pegando os valores retornados por esses metodos e exibe em JLabels, simples assim…

  • A aplicação é em Swing

  • A versão da minha jvm é 1.6.0 up 10.

Bom, eu acabei de ler aquele resumo que vc sugeriu, muito interessante !!! aquela parte de evitar o uso de finalizadores, eu ja tinha lido em algum lugar, mas ali estava mais explicado, inclusive uma maneira de garantir que o finalize() do objeto seja executado, utilizando um bloco try com finally…

Eu tenho uma pergunta, esse metodo finalize(), ele é chamado pelo gc quando o gc verifica que o objeto em questao nao possui mais nenhuma referencia certo? até onde eu sei, o metodo finalize() deve ser usado para atribuir null a todos os objetos usado pela classe, para que o gc possa coletar eles tbem, é isso mesmo? vi isso nesse link http://imasters.uol.com.br/artigo/3148/ajudando_o_garbage_do_java, ou o método finalize() quando for sobreescrito deve ter outra funcionalidade? o que exatamente ele tem q fazer?

to ficando cada vez mais confuso rsrsrs, achei este topico http://www.guj.com.br/posts/list/98674.java e o colega thingol diz que o finalize() atrapalha o gc. Gostaria de uma explicação sobre isso…

bom, por enquanto eu acho q é só… t+

Olá Cleiton…

[quote=cleiton herrmann] o que exatamente ele tem q fazer?

[quote]

Bem para falar do finalize, nada melhor do que quem fez neh? rs!
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html#finalize()

Mas inda sobre o consumo de mémoria, eu aconselho a você dar uma olhadinha em algumas ferramentas que monitoram a mémoria. Certa vez eu vi um, do qual não me lembro o nome, que inclusive dizia qual era a quantidade de memoria usada por instância.
Talvez o consumo da mémoria não seja por telas do Swing, mas até por outra parte do sistema.

Sou daqueles que vota por uma olhada geral no sistema, ao invez de usar estrategias como a invocação do finalize().
Mesmo porque quando eu tentava fazer esse tipo de coisa, havia algo de muito errado por traz.

Use uma ferramente de Profiling só pra gente tirar a duvida.
No Google você vai achar boas referencias sobre esse tipo de software.

[]'s

JL

É eu comecei a ler sobre o assunto e achei que implementar o finalize() seria uma boa, mas ja mudei de ideia, realmente vale pensar bem na estrutura do programa, cuidar o que se faz com os objetos ao invés de ficar tentando forçar o gc…

Eu usei agora o NetBeans profiler, mas como foi a primeira vez, achei meio confuso, tenho que dedicar mais tempo à essa ferramenta pra poder dar detalhes aqui…

Mas enfim, eu alterei a maneira de usar algumas telas de consultas aqui, e realmente ja melhorou bastante o uso de memória, mas mesmo assim, ainda esta só aumentando e nunca diminuindo a qtde de memória usada…

Por exemplo, se eu abrir e fechar a tela de vendas umas 50 vezes ± vai lançar a excessao java.lang.OutOfMemoryError: Java heap space, ele vai alocando memoria, alocando memoria, usando cada vez mais até lançar a excessao…

[quote=cleiton herrmann]É eu comecei a ler sobre o assunto e achei que implementar o finalize() seria uma boa, mas ja mudei de ideia, realmente vale pensar bem na estrutura do programa, cuidar o que se faz com os objetos ao invés de ficar tentando forçar o gc…

Eu usei agora o NetBeans profiler, mas como foi a primeira vez, achei meio confuso, tenho que dedicar mais tempo à essa ferramenta pra poder dar detalhes aqui…

Mas enfim, eu alterei a maneira de usar algumas telas de consultas aqui, e realmente ja melhorou bastante o uso de memória, mas mesmo assim, ainda esta só aumentando e nunca diminuindo a qtde de memória usada…

Por exemplo, se eu abrir e fechar a tela de vendas umas 50 vezes ± vai lançar a excessao java.lang.OutOfMemoryError: Java heap space, ele vai alocando memoria, alocando memoria, usando cada vez mais até lançar a excessao…[/quote]

Hum… Deixa eu fazer uma pergunta…
Essa sua tela de vendas, ela por acaso faz consultas ao banco, e faz uso de outras frameworks além do Swing?

Ela faz consultas e tbem insere registros em varias tabelas, vendas, itens venda, parcelas, lancamentos.
Eu uso o hibernate pra fazer a comunicacao, e para isso tenho uma classe chamada HibernateUtil, e outra chamada DAO, e eu aplico o padrao singleton na classe DAO, ja o HibernateUtil eu declaro um objeto global em cada tela, por causa da sessao…

Até vou dar uma olhada nisso, quem sabe nao esteja ai o problema do consumo excessivo de memória…

mas acredito que nao, pq teoricamente quando eu fecho a tela de vendas por exemplo, o objeto HibernateUtil que eu uso nela, teria que ser destruido nao é?

[quote=cleiton herrmann]Ela faz consultas e tbem insere registros em varias tabelas, vendas, itens venda, parcelas, lancamentos.
Eu uso o hibernate pra fazer a comunicacao, e para isso tenho uma classe chamada HibernateUtil, e outra chamada DAO, e eu aplico o padrao singleton na classe DAO, ja o HibernateUtil eu declaro um objeto global em cada tela, por causa da sessao…

Até vou dar uma olhada nisso, quem sabe nao esteja ai o problema do consumo excessivo de memória…

mas acredito que nao, pq teoricamente quando eu fecho a tela de vendas por exemplo, o objeto HibernateUtil que eu uso nela, teria que ser destruido nao é?[/quote]

Dê uma olhadinha no resultado das consultas.
Para telas muito complexas, e objetos muito grandes, eu sou daquele que vota pra trazer somente o necessário.
Pra isso o hibernate tem um sistema de retorno em Map que é muito util.

Eu tava analizando minha classe HibernateUtil, e sempre que eu crio um objeto HibernateUtil, eu crio uma SessionFactory tbem, entao eliminei isso agora, fiz uma classe no padrao singleton, pra criar somente uma SessionFactory e me fornecer sempre a mesma…

E de fato, fui testar agora, e resolveu o problema, agora meu sistema é iniciado e aloca 12376 Kb de memória, eu abri e fechei a tela de vendas umas 50 vezes aqui, e ele manteve somente os 12376 Kb alocados, nao alocou mais nd…

O problema era no HibernateUtil mesmo que ficava criando varios SessionFactory… Ufa, agora estou tranquilo, huahiahiuhaiua

E tem mais uma, sobreescrevendo o metodo finalize() e dentro dele atribuindo null a todos os objetos da classe, ou nao sobreescrevendo o metodo finalize(), tem o mesmo resultado, fica nos 12000 à 12500 Kb alocado e nao passa disso…

[quote=cleiton herrmann]Eu tava analizando minha classe HibernateUtil, e sempre que eu crio um objeto HibernateUtil, eu crio uma SessionFactory tbem, entao eliminei isso agora, fiz uma classe no padrao singleton, pra criar somente uma SessionFactory e me fornecer sempre a mesma…

E de fato, fui testar agora, e resolveu o problema, agora meu sistema é iniciado e aloca 12376 Kb de memória, eu abri e fechei a tela de vendas umas 50 vezes aqui, e ele manteve somente os 12376 Kb alocados, nao alocou mais nd…

O problema era no HibernateUtil mesmo que ficava criando varios SessionFactory… Ufa, agora estou tranquilo, huahiahiuhaiua

[/quote]

Resolvido?

Sim sim, resolvido e comprovado que um código bem planejado/estruturado nao vai causar problemas quanto a utilização dos recursos da maquina…

Vlw a ajuda e as ideias Mero_Aprendiz !!!

t+

Uma dica. Quando tiver problemas assim, não perca tempo conjecturando. Use um profiler. O netbeans possui um excelente profiler que vai indicar para você que classe está ocupando memória, quanta memória está sendo ocupada, etc. Analisando esse dado, você vai direto ao ponto onde o problema está. Por que usar um método rudimentar, como o que você descreveu, se você tem nas mãos uma ferramenta poderosa e precisa de graça???

O profiler é facílimo de usar. Dá uma olhadinha:
http://www.netbeans.org/kb/55/profiler-tutorial.html
http://www.netbeans.org/features/java/profiler_pt_BR.html

Ah, e muito cuidado com variáveis estáticas, como as encontradas no seu Singleton! Elas seguram referências fortemente, o que muitas vezes torna suas classes incoletáveis. Lembre-se o garbage collector existe, mas ele só funcionará caso sua classe não contenha mais referências! Portanto, a preocupação de desreferenciar deve existir em algum momento, removendo o listening the algum objeto (removeListener não existe a toa) ou evitando variáveis estáticas, já que elas nunca morrem.

Ah sim, claro que é bom ter um medidor de memória na sua aplicação, usando os métodos que você descreveu. Eu mesmo tenho um na minha, dá uma olhada:
http://www.guj.com.br/posts/list/118505.java#642011

1 curtida

Blz vinigodoy, com certeza é melhor mesmo, eu que o diga rsrsrsr, ja estou dando uma estudada no netbeans profiler…

vlw t+

Olá, Pessoal.
Muito interessante o tópico que está sendo tratado.

Estou enfrentando o mesmo problema de OutOfMemory relatado, porém em uma aplicação Web (JSF).

Utilizei o profiler do Netbeans 6.5 e o resultado me deixou curioso.

Pelo profiler notei que minhas classes de negócio estão consumindo pouco recurso, mas mostra uma grande quantidade de memória sendo alocada por referências a char[], byte[], byte[][][], etc…

Estes arrays de char e byte não estão sendo gerados por minhas classes de negócio.
Desconfio que sejam referências aos JSP das páginas da aplicação que são abertas.

Alguém saberia dizer do que se trata e como liberar a memória alocada por esses arrays?

Obrigado