Problemas com Java Heap Space no RETORNO de uma consulta a uma base de dados Oracle

Galera,

Boa tarde.

Tenho uma aplicação que faz uma consulta numa base de dados Oracle que tem mais de 21 milhões de tuplas na tabela e tenho de memória disponível na JVM 4.0 GB. Porém, no trabalho quando o usuário tenta acessar a funcionalidade tentando realizar a consulta, ele não tem resposta e a aplicação cai por time out e, sempre no log da aplicação aponta o famoso problema de java.lang.OutOfMemoryError: Java heap space.

Alguém poderia me dar uma idéia de como faço para resolver esse problema?

Filtrar os resultados. Ninguém vai olhar para uma tabela com 21 milhões de linhas…

[quote=LeandroGM007]Galera,

Boa tarde.

Tenho uma aplicação que faz uma consulta numa base de dados Oracle que tem mais de 21 milhões de tuplas na tabela e tenho de memória disponível na JVM 4.0 GB. Porém, no trabalho quando o usuário tenta acessar a funcionalidade tentando realizar a consulta, ele não tem resposta e a aplicação cai por time out e, sempre no log da aplicação aponta o famoso problema de java.lang.OutOfMemoryError: Java heap space.

Alguém poderia me dar uma idéia de como faço para resolver esse problema?[/quote]

  1. Filtre a consulta (para que serve o “where”?)

  2. Use um ResultSet que seja “forward only”, e pegue os dados e os jogue em um arquivo à medida que você os vai lendo. Não guarde os dados em uma lista na memória senão alguma coisa vai estourar.

4 GB de memória parece muito mas quando você vai recuperar resultsets grandes você vai ver que isso é relativamente pouco.
Só para ter uma idéia, uma String com 20 caracteres ocupa mais ou menos 20 x 2 + 8 + 8 + 16 = 72 bytes, em vez dos 20 bytes que você espera.
E mesmo que você tenha 4GB no seu computador, se você estiver rodando uma JVM de 32 bits (que é normalmente o caso no Windows de 32 bits) você só tem disponível para o heap cerca de 1,5 GB.

A aplicação já faz o filtro. É impossível retornar todos os registros da tabela, pois, sempre quando o usuário tenta fazer uma consulta, o filtro é efetuado através de um código correspondente a um atributo da tabela.

Quando você roda seu programa, você o faz com um atalho (normalmente uma batch ou script) que ajusta os valores corretos de memória? Não adianta você ter 4Gb de memória no seu computador se você não acertar o parâmetro -Xmx (que por padrão é um valor muito baixo, acho que uns 50 ou 100 MB, insuficientes para qualquer aplicação Swing que se preze).

entanglement

Através da aplicação faço a consulta na base confirme o filtro desejado pelo usuário e já tenho uma cláusula where que ‘sempre’ filtra a busca pretendida pelo usuário através de um código do cadastro do usuário. Uso o servidor de aplicação do Jboss e nele já tenho configurado o parâmetro de 4 GB da JVM e a máquina onde está instalada a aplicação tem 12 GB.

Aqui em casa acesso a aplicação no ambiente de produção usando o meu notebook e consigo efetuar a consulta e ter o retorno da aplicação com sucesso. Já cheguei a ter como resultado mais de 1600 páginas paginadas com mais de 20.000 registros, e no trabalho qualquer tentativa independente do computador sendo utilizado a aplicação no ambiente de produção cai por time out devido a falta de espaço na memória.

Eu vou verificar no código a questão do ResultSet como a busca é efetuada e aviso posteriormente.

Desde já agradeço pela atenção.

[quote=entanglement][quote=LeandroGM007]Galera,

Boa tarde.

Tenho uma aplicação que faz uma consulta numa base de dados Oracle que tem mais de 21 milhões de tuplas na tabela e tenho de memória disponível na JVM 4.0 GB. Porém, no trabalho quando o usuário tenta acessar a funcionalidade tentando realizar a consulta, ele não tem resposta e a aplicação cai por time out e, sempre no log da aplicação aponta o famoso problema de java.lang.OutOfMemoryError: Java heap space.

Alguém poderia me dar uma idéia de como faço para resolver esse problema?[/quote]

  1. Filtre a consulta (para que serve o “where”?)

  2. Use um ResultSet que seja “forward only”, e pegue os dados e os jogue em um arquivo à medida que você os vai lendo. Não guarde os dados em uma lista na memória senão alguma coisa vai estourar.

4 GB de memória parece muito mas quando você vai recuperar resultsets grandes você vai ver que isso é relativamente pouco.
Só para ter uma idéia, uma String com 20 caracteres ocupa mais ou menos 20 x 2 + 8 + 8 + 16 = 72 bytes, em vez dos 20 bytes que você espera.
E mesmo que você tenha 4GB no seu computador, se você estiver rodando uma JVM de 32 bits (que é normalmente o caso no Windows de 32 bits) você só tem disponível para o heap cerca de 1,5 GB.
[/quote]

++

Eu ainda insisto. Qual a necessidade você trazer em uma tela de busca, todos os 20.000 registro que você tanto fala ? Sendo que o usuário só vai ver uns 20 por página ?

Dependendo do tipo de dado que você estiver filtrando no seu WHERE, a consulta pode demorar mais, ou pode ser mais rápida, e sem contar que dependendo do banco, as avaliações de ordem das condições podem mudar (o que implica em tempo). Vou dar um exemplo no mysql bem básico:

1 - Pegue sua query, e faça um EXPLAIN suaQuery no banco e veja se é possível utilizar algum indice já existente, tente colocar na ordem dos wheres de acordo com seus indices.

2 - Use o LIMIT - esta é a regra mais importante!

3 - Se você tem uma quantidade de registros absurda, considere para fazer a paginação com a mesma consulta, POREM, trocando o select * FROM … por SELECT COUNT(1) AS registros FROM … ou SELECT COUNT(campo-de-maior-relevancia-q-seja-indice-q-nunca-vem-null) AS registros FROM …
3.1 - Aqui não adianta você querer fazer a paginação com um list.size() pois os registros já estão na memória e pode parecer que não, mas 10 usuários apertando o submit duas vezes aqui propositalmente, eles derrubam sua aplicação sem esforço algum.
3.2 - DEPENDENDO da forma como seu WHERE está feito, quase sempre é mais rápido para o banco de dados fazer um COUNT de 100.000 linhas, do que, separar 100.000 linhas para devolver para um processo, e, depois, o java ter que mapear essas 100.000 linhas na memória (Se tiver JPA/Hibernate aqui com lazy, é sentar para chorar :stuck_out_tongue: ).

Trolltopic:

String has length+24 bytes of overhead over byte[]:

	class String implements java.io.Serializable {
	    private char value[];  // 4 bytes + 12 bytes of array header
	    private int offset;    // 4 bytes
	    private int count;     // 4 bytes
	}

fonte: http://www.jwz.org/doc/java.html 8)