| Autor |
Mensagem |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/09/2011 11:15:33
|
jotinhaelloco
Thread.start()
![[Avatar]](/images/avatar/2e7fc7cb9bf8baacf29f1b7286976f53.png)
Membro desde: 03/07/2006 21:11:54
Mensagens: 27
Offline
|
Bom dia. Eu estou desenvolvendo uma aplicação que faz a manipulação de grandes informações de texto em um banco de dados. O problema, é que tenho um laço que faz inserções e ele gera muito lixo a cada iteração. Com tempo passei a ter o famoso erro de java.lang.OutOfMemoryError: Java heap space, ou seja, o espaço do heap se esgotou. A primeira alternativa para solucionar isso foi chamar o GC ao final de cada iteração com:
Sei que isso não é garantia de que ele irá passar, mas requisitando ele com grande frequencia, resolveu meu problema. Mas a aplicação ficou insuportavelmente lenta. Dai pensei, vou monitorar o espaço livre no heap, com:
para que quando ele chegue a um limite próximo do mínimo, eu chame o GC, melhorando assim a performace e diminuindo as chamadas desnecessárias. Algo do tipo:
Deu java.lang.OutOfMemoryError: Java heap space de novo, pois o GC não passava naquele exato momento.
Tentei então uma terceira alternativa, que seria a cada iteração, verificar a quantidade de espaço livre, e se ela estiver abaixo de um patamar, segurar a execução em um laço, até que o GC passe e libere mais memória. Algo do tipo:
Mas isso congela a aplicação. Alguém teria mais alguma sugestão?
Desde já agradeço!
This message was edited 1 time. Last update was at 22/09/2011 16:28:45
|
"Dai gloria ao Senhor por que ele é bom ! Eterna é a sua misericórdia!" |
|
|
 |
|
|
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/09/2011 11:33:03
|
entanglement
GUJ Hacker
Membro desde: 26/09/2009 09:18:56
Mensagens: 5750
Offline
|
Que tal usar um outro algoritmo de garbage collection, e tunar os parâmetros?
Por exemplo, se você usava java -cp . SeuPrograma parametros, você faria algo como:
java -XX:+UseG1GC -cp . SeuPrograma
ou então
java -Xincgc -cp . SeuPrograma
ou então
java -XX:+UseParallelOldGC -cp . SeuPrograma
Veja qual é que funciona melhor para você.
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/09/2011 11:35:40
|
saoj
JWizard
![[Avatar]](/images/avatar/2e7ceec8361275c4e31fee5fe422740b.png)
Membro desde: 09/03/2004 23:34:46
Mensagens: 2667
Localização: Chicago, EUA
Offline
|
Aumenta o heap com aquele parametro inicial do Java ou não cria tanto lixo. Reutilize os seus objetos.
Até daria para fazer o seu thread dormir enquanto a sua freeMemory() não aumenta, Ultimo caso tenta isso.
This message was edited 1 time. Last update was at 22/09/2011 11:38:08
|
Sergio A Oliveira Jr. - saoj
ExperiMENTA:
Mentawai = http://www.mentaframework.org - Full-stack Java Web Framework com Configuracão Programática
MentaQueue = http://mentaqueue.soliveirajr.com - Queue de alta-performance.
MentaLog = http://mentalog.soliveirajr.com - Non-intrusive, fast, garbage-less, colored and straightforward logging
MentaBean = http://mentabean.soliveirajr.com - Tiny ORM with SQL Builder
MentaRegex = http://mentaregex.soliveirajr.com - Perl-style regex for Java.
MentaContainer = http://mentacontainer.soliveirajr.com - Straightforward IoC, DI e Auto-Wiring
Space4J = http://www.space4j.org - Banco-de-dados de Objetos em Memória
Options-Lib = https://github.com/saoj/options-lib - Ruby classes para ter acesso as opcoes do Yahoo Finance
Selleto = http://www.selleto.com.br
Flipinion = http://www.flipinion.com
Kawai = http://www.kawaiwiki.org
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/09/2011 11:40:50
|
FernandoFranzini
GUJ Master
![[Avatar]](/images/avatar/33f6c40df1060aa3c548ad2d499eced0.jpg)
Membro desde: 24/04/2009 12:58:16
Mensagens: 1541
Offline
|
Vc tem 3 opções... Se seu processo ta gastando mais memoria do que a alocada para JVM......
1) Aumentar a memoria
Complicado aqui...uma vez que quanto maior o texto, mais RAM na JVM vc vai precisar....então na verdade não resolve...apenas remedia temporariamente.
2) Reduzir os gastos
Aqui ja podemos caminhar melhor...
Por exemplo...
1)use JDBC BATCH...
2)use StringBuffer..
3)use paginação no processos ai..
4)Aplicar singleton para objetos compartilhados
5)liberar todos os ponteiros logo apos uso.
3) Fazer o passo 1 e passo1
Mesmo vc otimizando todo o possível, ainda sim seu processo ainda pode estar gastando mais memoria do que o disponivel. Por isso vc ainda tera que aumentar a memoria.
OBS - não vai adiantar esperar o GC passar se vc ta gastando mais do q vc tem....é questão de matemática simples.
This message was edited 2 times. Last update was at 22/09/2011 11:48:54
|
Fernando Franzini |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/09/2011 11:45:54
|
rmendes08
GUJ Master
![[Avatar]](/images/avatar/9ee855f3ce4dd40182183463232e2162.jpg)
Membro desde: 29/05/2008 14:09:28
Mensagens: 1617
Offline
|
Bom, na minha opinião, isso é caso para otimizar o algoritmo. Talvez você possa utilizar alguma abordagem divide-and-conquer, e processar os dados em partes.
|
"A Técnica é transformada em Arte por quem a emprega"
"O futuro pertence àqueles que acreditam na beleza de seus sonhos"
Computadores Fazem Arte
http://www.uaijug.com.br
"É importante estabelecer uma estrutura de alto nível, mas isso não significa criar uma infinidade de diagramas de classes detalhados." |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/09/2011 12:28:28
|
grunfeldt
Thread.start()
![[Avatar]](/images/avatar/60ccb8c0b709b4e29f47b5d62086314b.jpg)
Membro desde: 11/12/2006 14:06:55
Mensagens: 35
Offline
|
Você nem precisa ficar forçando o gc a rodar,
o gc sempre roda quando um 'pedaço' do seu heap esta cheio de referências...
O melhor seria se você garantisse ou otimizasse ao máximo esse grande número de objetos que você esta mantendo alguma referência porque ele só trava quando não tem mais como se livrar desses caras mesmo...
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/09/2011 12:49:33
|
FernandoFranzini
GUJ Master
![[Avatar]](/images/avatar/33f6c40df1060aa3c548ad2d499eced0.jpg)
Membro desde: 24/04/2009 12:58:16
Mensagens: 1541
Offline
|
grunfeldt wrote:Você nem precisa ficar forçando o gc a rodar,
o gc sempre roda quando um 'pedaço' do seu heap esta cheio de referências...
O melhor seria se você garantisse ou otimizasse ao máximo esse grande número de objetos que você esta mantendo alguma referência porque ele só trava quando não tem mais como se livrar desses caras mesmo...
Corretíssimo....
Não existe regra, mas quando o HEAP esta em media de 70% o GC ja começa a se movimentar para liberar....
Resumindo:
Trabalhar com memoria no Java é como uma brincadeira de criança....
- a memoria é copo com um tamanho determinado.
- cada vez vc cria um objeto (new) vc coloca um gota de água nesse copo.
Como funciona?
- Quando vc inicia a aplicação, vc ja coloca um pouco de água...tipo uns 20% do copo (pelos gastos do objetos iniciais)
- Enquanto a aplicação ta rodando, que vai enchendo de água....(gastando objeto durante o uso)
- Quando a água começa ficar acima dos 70% , o GC ja vai tentando retirar/derramar essa agua do copo (retirar os objetos sem referencia)
- Se o gc conseguir ele, esvazia esse copo...tudo volta ao ciclo...
- Se o gc não conseguir....a agua cai do copo java.lang.OutOfMemoryError kkkkk
Motivos de Falta de Memoria?
1) A solução esta gastando memoria desenfreadamente - falta de uma arquitetura correta ou desenvolver despreparado.
Como corrigir? Abrir o código e otimizar. Existem muitas e muitas práticas....
2 A solução esta gastando memoria corretamente, mas ainda não é suficiente.
Se a aplicação esta ok e otimizada...unica coisa q pode ser feito é aumentar a memoria...pq a solução precisa de mais memoria!!!
Acontece quando muito principalmente em aplicações web quando o numero de usuário simultâneo vai aumento.
|
Fernando Franzini |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/09/2011 14:03:26
|
juliocbq
GUJ Expert
![[Avatar]](/images/avatar/153704bb24a28e9a6bb49e8ffde1492e.jpg)
Membro desde: 13/11/2008 12:10:18
Mensagens: 3927
Offline
|
grunfeldt wrote:Você nem precisa ficar forçando o gc a rodar,
o gc sempre roda quando um 'pedaço' do seu heap esta cheio de referências...
O melhor seria se você garantisse ou otimizasse ao máximo esse grande número de objetos que você esta mantendo alguma referência porque ele só trava quando não tem mais como se livrar desses caras mesmo...
Bem, é o contrário, de acordo com os artigos que li. Enquanto os endereços estão referenciados eles são a "velha geração", e são alocados no heap consumindo espaço. Não existe gato no planeta que faça o gc liberar essa memória, até porque ela está referenciada.
Uma maneira de forçar o coletor de lixo é atribuir null ao endereço. Como não há mais referência o ele já está marcado para ser coletado.
isso aqui é a "marca da morte"
diz que o pode ser coletado.
A solução do entanglement é muito boa. Ela pode resolver seu problema. No mais tente melhorar a sua lógia e reaproveitar mais os objetos alocados ao invés de coletá-los.
|
www.citrox.com.br |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/09/2011 14:04:19
|
jotinhaelloco
Thread.start()
![[Avatar]](/images/avatar/2e7fc7cb9bf8baacf29f1b7286976f53.png)
Membro desde: 03/07/2006 21:11:54
Mensagens: 27
Offline
|
entanglement wrote:Que tal usar um outro algoritmo de garbage collection, e tunar os parâmetros?
Por exemplo, se você usava java -cp . SeuPrograma parametros, você faria algo como:
java -XX:+UseG1GC -cp . SeuPrograma
ou então
java -Xincgc -cp . SeuPrograma
ou então
java -XX:+UseParallelOldGC -cp . SeuPrograma
Veja qual é que funciona melhor para você.
Cara, tentei os 3, nenhum deu certo... Acho que meu problema não é a frequência com que o GC passa, e sim o monte de lixo que estou deixando na memória...
saoj wrote:Aumenta o heap com aquele parametro inicial do Java ou não cria tanto lixo. Reutilize os seus objetos.
Até daria para fazer o seu thread dormir enquanto a sua freeMemory() não aumenta, Ultimo caso tenta isso.
Eu aumentei o tamanho do heap com -Xms192m -Xmx1024m, dai, ele rodou mais tempo, mas deu o mesmo erro de estouro de heap... Tentei também a estratégia do Thread.sleep() e não deu certo...
rmendes08 wrote:Bom, na minha opinião, isso é caso para otimizar o algoritmo. Talvez você possa utilizar alguma abordagem divide-and-conquer, e processar os dados em partes.
Na verdade, é isso mesmo que estou fazendo... Estou implementando um sistema distribuído...
FernandoFranzini wrote:Vc tem 3 opções... Se seu processo ta gastando mais memoria do que a alocada para JVM......
Acho que estou mesmo é gastando referências de mais... Deixo o código abaixo... Quem puder da um força plz
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/09/2011 14:08:06
|
FernandoFranzini
GUJ Master
![[Avatar]](/images/avatar/33f6c40df1060aa3c548ad2d499eced0.jpg)
Membro desde: 24/04/2009 12:58:16
Mensagens: 1541
Offline
|
Te feio mesmo em amigo...
Nem PreparetedStatement vc ta reusando...ta criando todo hora afffff......dai não
Outra coisa....vc deve usar BATCH....
|
Fernando Franzini |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/09/2011 14:10:08
|
jotinhaelloco
Thread.start()
![[Avatar]](/images/avatar/2e7fc7cb9bf8baacf29f1b7286976f53.png)
Membro desde: 03/07/2006 21:11:54
Mensagens: 27
Offline
|
FernandoFranzini wrote:Te feio mesmo em amigo...
Nem PreparetedStatement vc ta reusando...ta criando todo hora afffff......dai não
Outra coisa....vc deve usar BATCH....
Opa, pela forma que eu fiz eu achei que estava reusando, pelo fato de não fazer new toda hora ... Como faço para mudar? De que se trata BATCH?
|
"Dai gloria ao Senhor por que ele é bom ! Eterna é a sua misericórdia!" |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/09/2011 14:12:53
|
juliocbq
GUJ Expert
![[Avatar]](/images/avatar/153704bb24a28e9a6bb49e8ffde1492e.jpg)
Membro desde: 13/11/2008 12:10:18
Mensagens: 3927
Offline
|
dá uma repassada nas suas listas.
se você usa add sem remove ela vai crescer desordenadamente como deve ser mesmo.
|
www.citrox.com.br |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/09/2011 14:15:33
|
ViniGodoy
Moderador
![[Avatar]](/images/avatar/1921493b5362e63fbe8983f4bd54157d.png)
Membro desde: 11/12/2006 08:22:01
Mensagens: 20580
Localização: Curitiba/PR
Offline
|
Se dá OutOfMemoryError é porque necessariamente, você tem objetos referenciados. O motivo não é por culpa do GC, ou porque o GC deixou de rodar.
O GC sempre rodará antes de dar um OutOfMemoryError.
Portanto, chamadas a System.gc() são completamente inúteis nesse contexto. Seus usos são muito raros, geralmente para preparar a VM para um processamento de tempo real.
No seu caso, eu começaria limpando a bagunça que está seu código e também usaria o profiler para identificar o gargalo.
Também reveria com cuidado essas consultas aí, especialmente porque não estou vendo nenhum comando de "close" em seus statements.
|
@ViniGodoy - Lattes
Tem dúvidas de Java? Poste no fórum! Não respondo dúvidas de java via MP!
Ponto V! - Desenvolvimento de Jogos Profissional - @Pontov - Facebook
Projeto Towel - Swing de uma forma inteligente (Novo lar do ObjectTableModel e do Auto-Filtro).
Ei... você está usando DefaultTableModel no seu projeto??
Não faça isso! Veja: http://www.guj.com.br/posts/list/15/199067.java#1001295 |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/09/2011 14:18:56
|
FernandoFranzini
GUJ Master
![[Avatar]](/images/avatar/33f6c40df1060aa3c548ad2d499eced0.jpg)
Membro desde: 24/04/2009 12:58:16
Mensagens: 1541
Offline
|
Claro q não....leia o JAVADOC do metodo....
"Creates a PreparedStatement object for sending parameterized SQL statements to the database. "
Reusar o prepareted é criar uma vez....
realmente vc ta fazendo da pior forma....
De qualque forma.....vc deve usar BATCH - http://www.jdbctutorial.net/jdbc-batch-update-oracle.php
Vai melhorar, muito mas ainda pode estorar...não tem como eu garantir...
Na sua abordagem vc ta gastando muito objetos JDBC e esta fazendo um viagem TPC a cada SQL...
Cada uma abre a transação automática do JDBC, a não ser q vc configurou ao contrario....
No BATCH vc vai preencher todos os SQL e vai ir no banco 1 vez por transação, executando TODOS sql de um unica vez!
This message was edited 4 times. Last update was at 22/09/2011 14:23:14
|
Fernando Franzini |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/09/2011 16:27:32
|
jotinhaelloco
Thread.start()
![[Avatar]](/images/avatar/2e7fc7cb9bf8baacf29f1b7286976f53.png)
Membro desde: 03/07/2006 21:11:54
Mensagens: 27
Offline
|
Seguindo as dicas do FernandoFranzini e do ViniGodoy, funcionou belezinha. Relmente, a cada iteração do laço eu gerava mais lixo. O código ficou assim:
|
"Dai gloria ao Senhor por que ele é bom ! Eterna é a sua misericórdia!" |
|
|
 |
|
|