Out of memory (Websphere + Ibatis + Struts 1.1)

15 respostas
AndreAlves

Estou com um problema em ambiente de produção Websphere, onde uma aplicação que utiliza os frameworks Ibatis e Struts 1.1 está derrubando o WAS por out of memory.

Eu usei o heap analyzer da IBM para investigar os dumps e aparentemente o erro acontece no retorno de uma query no banco de dados Oracle.

A aplicação web chama uma stored procedure no Oracle através do Ibatis. Esta procedure popula uma tabela temporária (global temporary table) e posteriormente é feito um SELECT nesta tabela (tudo isto está dentro de uma transação).

Alguém já teve um problema semelhante?

Obrigado.

15 Respostas

ricardolecheta

uma vez me chamaram para fazer uma consultoria num problema destes…

o sql estava levantando ± uns 350 mb, e depois ainda ficava na sessao do usuario… se 2 ou 3 usuarios fizessem esta busca, ja era…

mas no seu caso só olhando para saber… outofmemory ou é um loop infinito que daria no ambiente local tb… ou é porque vc pode nao estar liberando recursos,… fechando statements, resultsets, etc… ou sua query pode ser gigantesca.

Aldrin_Leal

Você precisa ajustar a consulta para, entre outras coisas, utilizar o RowHandler:

dc.rec1

Recomendo voce utilizar um profiler como JProfiler para ter um analise completo da tua aplicação.

http://www.mouseoverstudio.com/blog/?p=67

AndreAlves

Aldrin Leal

Pelo o que eu entendi, o RowHandler é um mecanismo de manipular o resultado da query linha por linha antes de o Ibatis popular a Collection.

Você tem alguma dica de como utilizar o RowHandler para resolver este problema?

Aldrin_Leal

O termo correto não é antes, e sim ao invés.

O fato é o seguinte: Muitos drivers JDBC (MySQL, particularmente), não usam a metáfora de cursor no servidor, que seria o ideal. Isso pode acontecer por vários motivos (em particular, pelo próprio servidor não oferecer - calma, o MySQL oferece, mas drivers de alguns bancos acabam não fazendo), mas o motivo principal é aquela velha tendência do anaprodégua não chamar o close no resultset.

Ok, dito isso, vamos comentar sobre o seu pobrema. Bem, o que você pretende fazer com os dados, afinal de contas? Se tem tabela temporária, é provavelmente algum processamento oneroso.

Se você tá fazendo isso em uma aplicação web (a julgar pelo WebSphere), minha primeira sugestão é: desvincule isso do request, usando algo como o Quartz, Message Driven Beans, ou o próprio recurso de Asynchronous Beans do WebSphere, como também o de Object Pools.

Em um projeto em particular, lembro-me que o mesmo exigia salvar quantidades absurdas de dados em consultas. A abordagem foi semelhante, mas um pouco mais ortodoxa: O nosso RowHandler lia de uma consulta e… Salvava em outra. Mas a outra conexão era uma base de dados H2.

Pensando bem, uma saída intermediária seria você utilizar o CachedRowSet. Em particular, eu apenas me preocuparia em serializá-lo utilizando Fast-Infoset. Mas, eis, são apenas opiniões minhas. :slight_smile:

AndreAlves

Aldrin Leal

Os dados são utilizados em uma consulta. A Collection retornada pelo Ibatis é colocada na request e exibida para o usuário em um JSP.

O comportamento da aplicação está meio esquisito, pois está dando Out of memory mesmo quando o usuário não está solicitando um conjunto grande de dados. Eu estou utilizando o recurso de groupBy do Ibatis, para facilitar uma consulta de referência cruzada. Eu pesquisei no mail-archive do Ibatis, e acho que isso pode estar melando a aplicação:

http://www.mail-archive.com/[email removido]/msg10625.html

agodinho

Cara, tem certeza de quê a query está realemente okay? Não tá rolando cartesiano não? Executa a query com count pra ter certeza de que está tudo okay. Usei iBatis com querys grandes (gigantes) e apenas uma vez tive problemas com out of memory …

Por favor, copie a query e o xml aqui (a versão do ibatis tb ajuda). Com isso poderemos “ver” o quê está rolando …

Woody

AndreAlves

Tenho certeza absoluta que a query está correta. A query é super simples, utilizando apenas a tabela temporária (global temporary table) gerada pela stored procedure.

agodinho

Cara, posta aí o xml e o trecho de dao que está retornando essas linhas …

Aldrin_Leal

Você pode dar alguma idéia da ordem de magnitude? Em particular, coisas como quantos registros essa consulta devolve, e em quanto tempo (caso demore um pouco)

Olhando pela documentação do ibatis, vi que o groupBy pode gerar MUITOS resultados em memória. Então assim, uma tabela na ordem de centenas de milhares de registros pode acabar gerando vários detalhes que ocupam MUITA memória. Talvez o ideal seja você só ter esta chave e então, adotar uma estrutura de cache ou algo como o LazyMap, do commons-collections.

agodinho

Aldrin Leal, sei não. O iBatis resolveu a query. Depois de resolver a query o iBatis transfere os dados dentro do resultset para um TO qq (ou map) …

Pelo que o André falou o erro está nessa fase (se fosse na fase do sql teriámos um SQLException)

Insisto: posta o mapping e o sql aí …

Aldrin_Leal

agostinhost,

Desculpa, mas não entendi nada do que você falou. Na dúvida, vou usar o princípio de taxa sinal ruído e fingir que não ouvi nada :slight_smile:

agodinho

pq se dar ao trabalho de comentar então?

Aldrin_Leal

Diante das opções, me pareceu a menos rude. Obrigado pela atenção.

agodinho

sei …

Criado 30 de março de 2008
Ultima resposta 4 de abr. de 2008
Respostas 15
Participantes 5