[Resolvido] Hibernate e OutOfMemoryError

10 respostas
maiconramones

Boa tarde pessoal, estou com o seguinte problema preciso ler uma tabela que tem cerca de 700 mil registros e passar esses dados para uma outra tabela. Pra fazer isso eu utilizei os métodos setFirstResult e setMaxResults do hibernate, onde firstResult começa em zero e vai incrementando em 25000 passo o número máximo tbm como 25000, ou seja, busco do registro 0 a 24999, depois de 25000 a 49999 e por ai vai.
isso está dentro de um loop e quando chega na quarta iteração do loop, ou seja, carreguei e inseri 75000 registros ocorre erro de java.lang.OutOfMemoryError
Não consigo entender o pq disso uma vez que os resultados estão “paginados”.

Segue o trecho do loop:

totalInsert = this.total.countInsert();
		do {
			list.clear();
			list= this.packingListDao.findInsert(
					firstResult, 25000);

			for (PackingListItem packingListItem : list){
				count++;
				total++;

				// alguns new

				// algumas buscas em bds 
                                
                                // e os insert dos dados nas novas tabelas

				// atribuição de null para objetos que foram criados com o new
			}
			firstResult += 25000;
			System.gc();
		} while (count != totalInsert);

e o trecho do dao

@SuppressWarnings("unchecked")
	public List<PackingListItem> findInsert(final int firstResult,
			final int maxResult) throws Exception {
		return this.getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				String query = " from PackingListItem as packing where not "
						+ " exists ( select 1 from DpPackListItem as dp where "
						+ " dp.cdSExport = packing.cdPackingItem "
						+ " and dp.cdSExport = packing.cdPackingList )";
				Query sqlQuery = session.createQuery(query);
				sqlQuery.setMaxResults(maxResult);
				sqlQuery.setFirstResult(firstResult);
				
				return sqlQuery.list();
			}
		});
	}

10 Respostas

rodrigo_gomes

Olá,

Isso vai te ajudar:
http://www.hibernate.org/hib_docs/reference/en/html/batch.html

O outofmemory deve ta acontecendo pq os objetos estão em cache na session.

[]´s

luistiagos

tente aumentar a memoria e a paginação de sua jvm

luistiagos

se estiver usando eclipse vc pode ir nas propriedades do atalho dele e adicionar -Xms 64M -Xmx 600M
isto aumenta a memoria e a paginação

Henrik

Eu teria feito usando jdbc puro

Voce ja tentou o profile?

maiconramones

opa e ai gurizada.

@rodrigo_gomes, bah não posso fazer bath dos insert porque tem algumas regras de negócio trash ai por baixo…

Teria alguma maneira de desabilitar totalmente o cache da session??

@luistiagos, realmente este procedimento é uma gambiarra, porque imagina se a tabela continuar crescendo… daqui a pouco eu vou ter que aumentar a memória pra quanto?? 1 ou 2 giga? fica inviável essa solução.

@Henrik, existe essa possibilidade fazer esse select com jdbc puro sem prender a função que limita o nº de registros e o firstResult ao um bd especifico?? eu não me lembro mais(isso é o que dá o cara se acostumar com o hibernate :frowning: )

nbluis

Eu também acho que JDBC puro traria um melhor resultado.
Mas independente disso.

Diminua o número de objetos por iteração, diminua drasticamente.

Faça a declaração de sua lista dentro do bloco.

totalInsert = this.total.countInsert();  
 do {  
    System.gc();  
    List<PackingListItem> list = this.packingListDao.findInsert(firstResult, 5000);  
     
             for (PackingListItem packingListItem : list){  
                   count++;  
                   total++;  
               }  
               firstResult += 5000;  
           } while (count != totalInsert);

De qualquer maneira o hibernate vai criar uma nova lista a cada iteração, e coloque o System.gc na primeira linha do código.

Outra coisa, não necessita atribuir null aos objetos criados, ao final do blogo eles ja ficam disponiveis para a gc.
Se queres delimitar escopo vida, crie blocos para defini-los dentro do bloco while.

Por enquanto é isso…

maiconramones

@nbluis , existe a possibilidade de fazer esse select em jdbc puro sem se “prender” alguma função especifica do banco??

Mauricio_Linhares

maiconramones:
opa e ai gurizada.

@rodrigo_gomes, bah não posso fazer bath dos insert porque tem algumas regras de negócio trash ai por baixo…

Teria alguma maneira de desabilitar totalmente o cache da session??

Não desabilitar, mas você pode remover um objeto do cache e ele vai ser coletado:

http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html#evict(java.lang.Object)

nbluis

Na verdade o hql que apresentaste vai gerar um sql dentro dos padrões ANSI, que roda em quase todos (senão todos) os banco de dados relacionais do mercado.
Daria sim, sem problemas.

maiconramones

Bom eu vou fazer alguns testes, como são muuiiiitos registros vai demorar um pouquiho mas assim q eu tiver algum retorno eu posto aqui.

Por enquanto obrigado pessoal, e feliz ano novo pra todos ae.

Abraço.

Criado 27 de dezembro de 2007
Ultima resposta 28 de dez. de 2007
Respostas 10
Participantes 6