String X StringBuffer

Senhores,

Estou tendo um grande problema! Estou trabalhando em uma aplicação que foi desenvolvida com " as piores " formas imagináveis!
Nessa aplicação temos algumas classes genéricas (gigantescas) e, apenas com métodos “static” e muitas…muitas…muitas STRINGS (na maioria dos casos, são SELECT grandes)

Exemplo:

public static String sql_1_de_100000(paramentros){
   String sql = "";
   sql = "SELECT 1,2,3,4 ";
   sql += "FROM tabela;
   return sql;
}

1ª A aplicação é WEB, e até que restartamos o TOMCAT esses métodos ficam na memória né???
2ª Essas strings estão alocadas na “Área Permanente” da JVM, pois com o passar do tempo temos a “exception: PermGen”, e pelo que li, o garbage não coleta os objetos criados nessa área, a questão é: teria alguma forma de eu usar esses métodos de forma que tais objetos ocupem a área de memória Heap??? Assim quando não houverem mais referencias, nosso amigo Colector remove-os!

3ª O código abaixo cria novas String, devido o operador ‘+’ ??

public static String sql_1_de_100000(paramentros){
   String sql = "";
   sql = "SELECT 1,2,3,4 " + " FROM tabela;
   return sql;
}

4ª O código abaixo cria novas String, devido o operador + dentro do construtor StringBuffer??

public static String sql_1_de_100000(paramentros){
   StringBuffer sql = null;
   sql = new StringBuffer("SELECT 1,2,3,4 " + " FROM tabela");
   sql.append("where coluna = 2");
   return sql.toString();
}

Desde já agradeço!

Embora concatenar strings usando “+=” seja condenável, não deve ser isso que está dando problemas com suas aplicações. Esse problema de “permgen” é por outra causa; procure aqui no fórum.

1 - Os métodos ficam na memória a partir do momento que a classe é carregada, pois os mesmos são static.
2 - Refatore o código para não usar métodos estáticos em demasia, atente se não estão sendo deixados muitos recursos abertos por muito tempo ou se os mesmos não estão sendo liberados apropriadamente (conexões com banco por exemplo).
3 e 4 - Sim, desde que as mesmas já não estejam no pool de Strings.

Esse seu cenário é desenvolvimento ou produção?

Se for desenvolvimento isso é normal caso vc fique executando o projeto várias e várias vezes, pois ele fica sendo implantado novamente no tomcat várias e várias vezes e ele acaba estourando a memória… Uma forma de se livrar disso é colocar o projeto para rodar em debug e quando alterar o fonte de uma classe, vc usa o recurso “apply code changes” ou algo parecido da interface de depuração, ou então parar o tomcat de tempo em tempo (como vc já faz). Estou falando em um cenário de desenvolvimento no NetBeans beleza?

Até mais!

Então, em relação ao PermGen se deve a aplicação está mal estruturada e muitos objetos ficam pendurados na “Area Permanente”.
Estou tendo que dar um otimizada nela por inteira e essas classes citadas (apelidadas por nós aqui de MEGAZORDE) são gigantescas mesmo, e os métodos dessas classes são usados +/-90% da aplicação, seja para relatório, consultas, etc!! Ou seja, pelo que andei lendo sobre gerenciamento de memóra da JVM, essa “Area Permanente” é limitada, no caso aqui já aumentei para mais de 1GB e mesmo assim chega um determinado momento que é necessário dar um restart no TOMCAT.

Ai li uns artigos sobre otimização e algo que me chamou a atenção foi sobre String e como ela deve ser usada!!

Poderia usar Hibernate ?

Caso não possa, tem 2 opções:

1 - Aumenta o PermGenSpace.
2 - Troca tudo por StringBuffer sem essa concatenação e o gc vai poder coletar.

Analisando rapidamente consegui enxergar isso.

Espero ter te ajudado

Senhores,

A “área permantente” já está configurada, mesmo se eu coloque 10Gb para ela, cedo ou tarde teremos o problema, pois isso ocorre devido a má estruturação da aplicação.

Hoje, diante das circunstancias aqui é impossível implementar na aplicação um framework com hibernate, vale até pena citar que esse software foi desenvolvido por uma terceirizada e está uma bagunça só, as actions são tudo nela(regras de negócio, persistencia…etc);

Diante do tamanho dessas classes acredito que é serviço para quase um mês, só para substituir todas seus métodos.

Você pode utilizar StringBuilder que é mais rápido que StringBuffer.

Opa cara, beleza?
Fiz essa mesma pergunta a algum tempo atrás e alguns colegas me responderam (Vini, Renato, xjcd e Raff) e muito bem respondido e com educação.
Dá uma olhada no tópico

http://www.guj.com.br/posts/list/73639.java#387386

Abraço.

sql = new StringBuilder("SELECT 1,2,3,4 " + " FROM tabela");   

Uma linha dessas pode ser substituida por:

sql = new StringBuilder("SELECT 1,2,3,4 ").append(" FROM tabela");

Você elimina o +. e ainda mantém o código em uma linha.

O método append sempre retorna o próprio String Builder. Essa é uma técnica chamada invocation chaining. Portanto, você pode encadear vários appends juntos:

String x = new StringBuilder("Isso").append(" é").append(" um").append(" exemplo!").toString();

O Java não diferencia o sinal do + só por ele estar sendo usado com o StringBuffer. Portanto, você terá a mesma performance ruim.