Out of memory (Websphere + Ibatis + Struts 1.1)

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.

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.

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

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

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

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?

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:

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/user-java@ibatis.apache.org/msg10625.html

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

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.

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

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.

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í …

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:

pq se dar ao trabalho de comentar então?

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

sei …