Ajuda - Memory Leak em consultas Hibernate

Fala pessoal blz?

Estou desesperado atrás de ajuda, pois na finalização da minha aplicação identifiquei um memory leak e não consigo resolvê-lo…
Vamos Lá… Utilizo Hibernate com JPA, e para servidor de aplicações o tomcat 6.0… As minhas consultas são feitas da seguinte forma:

[code]public Collection carregarDados() {
logger.debug("** Carregar Indicadores Chamada…");

EntityManagerFactory entityManagerFactory = Persistence  
        .createEntityManagerFactory(PERSISTENCE_UNIT);  

EntityManager em = entityManagerFactory.createEntityManager();  
  
StringBuffer queryString = new StringBuffer(" Select ind FROM Indicador ind  ");          

Query findAllQuery = em.createQuery(queryString.toString());  
          
Collection<Object> indicadores = findAllQuery.getResultList();  
if (indicadores != null){  
    logger.debug("** Found " + indicadores.size() + " records:");  
}  
return indicadores;  

}[/code]

Então assim, eu compilo a aplicação ela roda numa boa, mas depois de um certo tempo, ela estoura o heap space com:

    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space  
        at java.util.Arrays.copyOf(Unknown Source)  
        at java.lang.AbstractStringBuilder.expandCapacity(Unknown Source)  
        at java.lang.AbstractStringBuilder.append(Unknown Source)  
        at java.lang.StringBuffer.append(Unknown Source)  
        at org.hibernate.sql.SelectFragment.toFragmentString(SelectFragment.java:133)  
        at org.hibernate.persister.entity.AbstractEntityPersister.concretePropertySelectFragment(AbstractEntityPersister.java:1191)  
        at org.hibernate.persister.entity.AbstractEntityPersister.concretePropertySelectFragment(AbstractEntityPersister.java:1163)  
        at org.hibernate.persister.entity.AbstractEntityPersister.generateSnapshotSelectString(AbstractEntityPersister.java:1205)  
        at org.hibernate.persister.entity.AbstractEntityPersister.postConstruct(AbstractEntityPersister.java:2979)  
        at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:431)  
        at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFactory.java:84)  
        at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:261)  
        at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1327)  
        at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:867)  
        at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:669)  
        at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:126)  
        at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:52)  
        at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:34)  
        at com.Syge.database.ServIndicadores.carregarDados(ServIndicadores.java:302)  
        at principal.main.main(main.java:41)  

Ja aumentei a memória da JVM, mas isso só prolonga o erro, o problema é como se a memoria fosse crescendo gradativamente e o Garbage Collector nunca coletasse os objetos inativos… Estou fazendo alguma coisa errado nas minhas consultas? Preciso de ajuda urgente, pois nem todo cliente tem condições de utilizar JVM com grande capacidade de memória… Preciso saber o que está causando esse memory leak, e o q esta consumindo a memória e não esta sendo removido do HEAP com o Garbage Collector

Desde Ja Agradeço
Att

Você precisa dar um close no EntityManager.

mas eu utilizo o spring, ele se encarrega de dar o close no
EntityManager

Eu não conheço muito de Spring, mas pelo que vi ali no seu código você ta instanciando o EntityManager sem o Spring.

sim ali ta sem spring, mas eu o utilizo esse codigo e antigo
o problema esta nas consultas, quando realizo uma consulta a memoria permgen aumenta e nao abaixa mais,
parece q garda em cache

Por que não posta o código atual?

	@Transactional(propagation = Propagation.REQUIRED)
	private AbstractPersistentObject findById(AbstractPersistentObject entity) throws TNSException
	{
		long id = entity.getId();
		String name = entity.getClass().getSimpleName();
		entity = this.entityManager.find(entity.getClass(), entity.getId());
		//this.entityManager.refresh(entity);

		if (entity == null)
		{
			TNSException e = new TNSException();
			e.setMensagemSimplificada(name + " com o ID: " + id + " não encontrado(a).");
			e.setMensagemTecnica(name + " com o ID: " + id + " não encontrado(a).");
			e.disparaExcecaoTratada();
		}
		
		this.entityManager.close();
		
		name = null;
		
		return entity;
	}

coloquei o close no final e nao adiantou !

Por que manda construir toda vez que chamar o metodo??

EntityManagerFactory entityManagerFactory = Persistence    
            .createEntityManagerFactory(PERSISTENCE_UNIT);    

pelo que aprendi , vc chama somente uma vez na vida de sua aplicação e vai usando essa instancia “singleton”

posta essa classe toda…

package persistence.db;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.AliasToBeanResultTransformer;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import application.exception.TNSException;
import application.util.CollectionNavigator;
import domain.entity.abstract_.AbstractPersistentObject;
import domain.entity.filter.FilterBase;
import domain.repository.IRepository;

@Repository("genericDao")
public class HibernateImpl implements IRepository<AbstractPersistentObject> 
{
	/*-------------------------------------------------------------------
	 * 		 					ATTRIBUTES
	 *-------------------------------------------------------------------*/
	@PersistenceContext
	private EntityManager entityManager;

	/*-------------------------------------------------------------------
	 *				 		    CONSTRUCTOR
	 *-------------------------------------------------------------------*/
	public HibernateImpl()
	{
	}

	/*-------------------------------------------------------------------
	 *				 		     BEHAVIORS
	 *-------------------------------------------------------------------*/	
	@Transactional(propagation = Propagation.REQUIRED)
	public AbstractPersistentObject save(AbstractPersistentObject entity)
	{
//		System.out.println( DefaultContextHolder.getClientDataSource() );
		entity.prepareSave();			

		if ( entity.getId() == null || entity.getId() == 0)
		{
			entityManager.persist(entity);
		}
		else {
			entityManager.merge(entity);
		}	
		return entity;
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public void remove(AbstractPersistentObject entity) throws TNSException
	{
		entityManager.remove(this.findById(entity));
	}
	
	@Transactional(propagation = Propagation.REQUIRED)
	private AbstractPersistentObject findById(AbstractPersistentObject entity) throws TNSException
	{
		long id = entity.getId();
		String name = entity.getClass().getSimpleName();
		entity = this.entityManager.find(entity.getClass(), entity.getId());
		//this.entityManager.refresh(entity);

		if (entity == null)
		{
			TNSException e = new TNSException();
			e.setMensagemSimplificada(name + " com o ID: " + id + " não encontrado(a).");
			e.setMensagemTecnica(name + " com o ID: " + id + " não encontrado(a).");
			e.disparaExcecaoTratada();
		}
		
		name = null;
		
		return entity;
	}
	
	@SuppressWarnings("unchecked")
	public List<AbstractPersistentObject> executeHql(String hql)
	{
		List<AbstractPersistentObject> lista = this.entityManager.createQuery(hql).getResultList();
		this.entityManager.flush();
		return lista;
	}
	
	@SuppressWarnings("unchecked")
	public List<AbstractPersistentObject> findByFilter(FilterBase filter)
	{
		filter.prepareCriteria();
		
		if( filter.getClass() == null )
			throw new TNSException("É necessário setar o CLASS!");
		Session session = (Session) entityManager.getDelegate();
		Criteria c =  session.createCriteria(filter.getClazz());
		
		for (int i = 0; i < filter.getListAttributes().size(); i++) 
		{
			switch (filter.getListOperator().get(i)) 
			{
			case FilterBase.LIKE:
				c.add(Restrictions.like(filter.getListAttributes().get(i), filter.getListValues().get(i)));
				break;
			case FilterBase.MAIOR_QUE:
				c.add(Restrictions.gt(filter.getListAttributes().get(i), filter.getListValues().get(i)));
				break;
			case FilterBase.EQUALS:
				c.add(Restrictions.eq(filter.getListAttributes().get(i), filter.getListValues().get(i)));
				break;
			case FilterBase.NOT_EQUAL:
				c.add(Restrictions.ne(filter.getListAttributes().get(i), filter.getListValues().get(i)));
				break;
			case FilterBase.BETWEEN:
			{
				if( (filter.getListValues().get(i) instanceof List) )
					c.add(Restrictions.between(filter.getListAttributes().get(i), 
							((List<Date>) filter.getListValues().get(i)).get(0), 
							((List<Date>) filter.getListValues().get(i)).get(1) ) );
				else
					throw new TNSException("Para utilizar BETWEEN é necessário passar uma lista com 2 posições(INICIO e FIM)!");
			}break;
			case FilterBase.JOIN:
				c.createCriteria(filter.getListAttributes().get(i)).add( 
						Restrictions.eq( "id", 
								((AbstractPersistentObject) filter.getListValues().get(i)).getId() ) );				
				break;
			}
		}
		
 		ProjectionList pr = Projections.projectionList();
		
		for (int p = 0; p < filter.getProjectionDataBase().size(); p++) 
			pr.add(Projections.property(filter.getProjectionDataBase().get(p)).as(filter.getProjectionentity().get(p)) );
			
		c.setProjection(pr);
		
		return c.setResultTransformer(new AliasToBeanResultTransformer(filter.getClazz())).list();
	}

	@SuppressWarnings("unchecked")
	public List<AbstractPersistentObject> getListLike(AbstractPersistentObject dto) throws TNSException
	{
		try {
			if (dto != null)
			{
				List<AbstractPersistentObject> result = new ArrayList<AbstractPersistentObject>();

				if(dto.getId() != null && dto.getId() > 0)
					result.add( this.findById(dto) );
				else
				{
					Session session = (Session) entityManager.getDelegate();
					Criteria c =  session.createCriteria(dto.getClass());

					c.add(Example.create(dto).enableLike(MatchMode.ANYWHERE).excludeZeroes().ignoreCase());

					/**
					 * Adicionado para o Criteria filtrar os campos que sao relacionamento
					 * Por padrao o Criteria IGNORA estes campos.
					 * O While, é para pegar possiveis relacionamentos nas classes PAI.
					 */
					Class<?> clazz = dto.getClass();	
					while (clazz != AbstractPersistentObject.class)
					{
						for (Field campo : clazz.getDeclaredFields()) 
						{
							if( campo.getType().getName().contains("domain.entity") )
							{
								campo.setAccessible(true);
								if( (campo.get(dto) != null) && (((AbstractPersistentObject) campo.get(dto)).getId() != null) && (((AbstractPersistentObject) campo.get(dto)).getId() > 0) )
								{
									c.add(Restrictions.eq(campo.getName(), campo.get(dto)));
									c.setFetchMode(campo.getName(), org.hibernate.FetchMode.JOIN);
								}
							}
						}
						clazz = clazz.getSuperclass();
					}
					
					result = c.list();
				}

				return result;
			}
			else
			{
				throw new TNSException("Não é possível fazer a busca com um objeto nulo.");
			}
		}
		catch (TNSException e){
			throw e;
		} catch (Exception e) {
			throw new TNSException("Falha ao carregar " + dto.getClass().getSimpleName() + ".", e);
		}

	}
	
	@SuppressWarnings("unchecked")
	public List<AbstractPersistentObject> listPesqParam(String query, Map<String, Object> params){
		Query q = this.entityManager.createQuery(query);
		for(String chave : params.keySet()){
			q.setParameter(chave, params.get(chave));

		}

		return q.getResultList();
	}
	
	@Override
	public void executeHqlUpdate(String query, Map<String, Object> params)
	{
		Query q = this.entityManager.createQuery(query);
		
		for(String chave : params.keySet()){
			q.setParameter(chave, params.get(chave));

		}
		
		q.executeUpdate();
		
	}
	
	@Override
	public void inicializaListasEntity(List<?> list){
		
		for (Object obj : list) {
			try {
				CollectionNavigator.navigate(obj);
			} catch (NoSuchMethodException e1) {
				e1.printStackTrace();
			} catch (SecurityException e1) {
				e1.printStackTrace();
			} catch (IllegalAccessException e1) {
				e1.printStackTrace();
			} catch (IllegalArgumentException e1) {
				e1.printStackTrace();
			} catch (InvocationTargetException e1) {
				e1.printStackTrace();
			}
		}
		
	}
}

tai classe inteira

[quote=rxavier][code]
@Transactional(propagation = Propagation.REQUIRED)
private AbstractPersistentObject findById(AbstractPersistentObject entity) throws TNSException
{
long id = entity.getId();
String name = entity.getClass().getSimpleName();
entity = this.entityManager.find(entity.getClass(), entity.getId());
//this.entityManager.refresh(entity);

	if (entity == null)
	{
		TNSException e = new TNSException();
		e.setMensagemSimplificada(name + " com o ID: " + id + " não encontrado(a).");
		e.setMensagemTecnica(name + " com o ID: " + id + " não encontrado(a).");
		e.disparaExcecaoTratada();
	}
	
	this.entityManager.close();
	
	name = null;
	
	return entity;
}

[/code][/quote]
Uma dúvida, pq só nesse método vc faz close() do EM?

nesse metodo eu coloquei o close pra fazer um teste, mas na verdade nao precisa

quais são as confs de JVM/Hardware x Acessos da sua aplicação?

isso está relacionado com um pico de uso?

as configuraçoes sao as padroes da JVM