[ Resolvido ] Limpar array de string com GC

17 respostas
S

Prezados,

Estou com um pequeno problema de utilização de recurso de memória em meu aplicativo e isso se deve ao fato de eu estar criando uma grande quantidade de arrays de strings com muitas posições. Nessa classe eu tentei forçar o uso do GC, atribuindo valor null a todos os arrays e chamando System.gc em seguida mas ainda sim obtive aquelas famigeradas exceções do Java heap Memory.

Para me certificar do que estava acontecendo, ativei o Profiler e fiquei monitorando o uso da memória e, de fato como eu esperava, a utilização de memória subia exponencialmente quando entrava nessa classe, em média o prograama consumia 20mb e, após criar os arrays, essa utilização subia para 303mb =/

Mas então, alguém sabe como devo fazer para melhorar isso? De preferência limpando, deletando, excluindo arrays gigantescos ou sei lá o que, ja tentei de tudo aqui, até rezei, mas sem resultados.

Abraço!

17 Respostas

T

Você provavelmente deve ter feito isto aqui:

String[] arr = new String[10000];

...

Arrays.fill (arr, null); // isto serve para liberar todas as posições do array de strings
arr = null;

ou não?

B

Strings são objetos diferentes… Eles ficam na Heap, mas ficam dentro do que chamamos pool de Strings.
Este pool não é acessado pelo GC, então os objetos criados não são recolidos, mesmo que suas referências estejam apontando para null.

Quando fazemos:

String str = "abc" + "def";

Na verdades estamos criando 3 String no pool. a String “abc” a String “def” e a String “abcdef”. Se você faz algum tipo de concatenação pode estar tendo este problema.

Existem duas classes em Java, StringBuffer e StringBuilder. A diferença entre elas é que uma usa métodos sincronizados e a outra não. Estas classes servem para evitar a criação de vários objetos quando você faz uma concatenação de String por exemplo.
De uma olhada nos métodos que estas classes lhe oferecem e talvez você consiga resolver seu problema.

T

De qualquer maneira, veja se é realmente necessário ter o tal array gigantesco. Por exemplo, ao trabalhar com arquivos-texto, costuma não ser necessário carregar o array inteiro na memória.

T

BrunoBastos:
Strings são objetos diferentes… Eles ficam na Heap, mas ficam dentro do que chamamos pool de Strings.
Este pool não é acessado pelo GC, então os objetos criados não são recolhidos, mesmo que suas referências estejam apontando para null.

Strings são objetos iguais aos outros. Eles só vão para o pool se eles forem constantes literais, ou se você usar o método “intern” da classe String.

Portanto deve haver alguma outra coisa que está afetando o seu programa.

B

thingol:
BrunoBastos:
Strings são objetos diferentes… Eles ficam na Heap, mas ficam dentro do que chamamos pool de Strings.
Este pool não é acessado pelo GC, então os objetos criados não são recolhidos, mesmo que suas referências estejam apontando para null.

Strings são objetos iguais aos outros. Eles só vão para o pool se eles forem constantes literais, ou se você usar o método “intern” da classe String.

Portanto deve haver alguma outra coisa que está afetando o seu programa.

Acredito que no problema dele não exista apenas uma declaração de Array… Provavelmente ele está atribuindo valor a todas as posições do mesmo, ou não receberia uma exceção na heap já que por default todos estariam referenciando null…

R

boas jovem!!

eu já tive um problema com Strings.
Trabalhei em um sistema “grande” que tinha algumas classes “megazorde”…
Vários métodos estáticos, e ainda por cima montavam SQL nela em String… não dá para descrever qual mal estava…só vendo mesmo. Bastava subir o tomcat e gerar algumas consultas que já dava “permgem”…
Para resolver isso, sem ter que modificar tudo …já que empresa não queria gastar muitas horas…afinal eram três classes que tinham basicamente todo “lógica de acesso a dados” do sistema… resolvi mesmo apenas deixando de usar String, usei apenas StringBuffer…

S

Obrigado pelas informações! Vou verificar as sugestões de todos e assim que resolver o problema posto a solução.

Mas por outro lado, trabalhar com ArrayList não poderia resolver essa questão também?

S

thingol:

Estou com um pequeno problema de utilização de recurso de memória em meu aplicativo e isso se deve ao fato de eu estar criando uma grande quantidade de arrays de strings com muitas posições.

Você provavelmente deve ter feito isto aqui:

String[] arr = new String[10000];

...

Arrays.fill (arr, null); // isto serve para liberar todas as posições do array de strings
arr = null;

ou não?

Não, eu fui direto:

arr = null;
System.gc();
T

Só para forçar um pouco a barra eu recomendo limpar o array antes de setar = null, porque pode ser que outra parte do seu programa também tenha uma referência para esse array. É por isso que eu faço tal coisa de “Arrays.fill”. O certo é não ter de fazer isso.

S

Estou trabalhando na importação de dados do excel e de um jeito ou de outro eu preciso criar arrays para armazenar e tratar as informações. Estou usando a API POI.

T

skabryanty:
Obrigado pelas informações! Vou verificar as sugestões de todos e assim que resolver o problema posto a solução.

Mas por outro lado, trabalhar com ArrayList não poderia resolver essa questão também?

Pode ser que sim. Trabalhar com grandes arrays é um pouco chato porque você é obrigado a:

  • Reservar mais espaço que você precisa;
  • Controlar a quantidade de dados que foram usados.
    Isso é um porre e eu evito usar arrays (em vez de ArrayList) só porque é bem chato controlar tudo isso.
S

Vou tentar o fill ai agora, já comento o resultado :slight_smile:

T

Se você vai importar dados, talvez seja necessário aumentar um pouco a memória disponível para o Java.

Isso é uma opção de linha de comando (-Xmx).

Exemplo

java -Xmx512m -jar MeuPrograma.jar
S

Nada =/

O fill não funcionou aqui, manteve a utilização de memória elevada ainda. Para terem idéia de 532mb estou usando 333mb. Muito alto. E isso acaba restringindo operações futuras dentro do software caso eu não venha a reinicializar o servidor.

S

Já apliquei isso aqui no catalina.sh e melhorou… ou melhor, mascarou o problema. Antes eu não conseguia nem executar essa classe, depois que adicionei esses parametros de xmx e xms deu uma melhorada mas ainda sim tem a limitação :smiley:

Bom seria se eu tivesse uns 30giga de memória kkkk

S

Continuo tentando aqui…

Percebi que se eu clicar no botão “Run Garbage Collection in Profiled Application” ele executa o garbage corretamente e limpa a memória!!!

Porém não estou entendendo por que quando eu chamo o System.gc() no sistema ele não faz o mesmo!

¬¬

S

Resolvido!!!

O problema estava no grande número de acessos que estava fazendo no banco de dados para armazenar e consultar as informações que obtinha do Excel, dai ocorria que mesmo encerrando as inserções buscas etc etc as “sessoes” ficavam abertas e como são muitas, passou a prejudicar o sistema.

Saída:

fechei todos os PreparedStatement, ResultSet e Conexões da vida e em seguida atribui valor nulo para todos os 3:

ps.close();
rs.close();
conn.close();

ps = null;
rs= null;
conn = null;

System.gc()

e funcionou beleza!
Engraçado que o problema passou longe dos arrays, como eu estava achando inicialmente. Nessas horas tem q investigar é tudo, até aquela virgula miserável que aparece faltando do nada hehe

O bom do java (e de outras coisas) é isso, cada leão que tu mata é um grande aprendizado :slight_smile:

Obrigado a todos!

Criado 28 de abril de 2009
Ultima resposta 28 de abr. de 2009
Respostas 17
Participantes 4