/ / Fuite de mémoire avec des requêtes JPA paginées sous JBoss AS 5.1 - java, hibernate, jpa, jboss5.x, hibernate-search

Fuite de mémoire avec des requêtes JPA paginées sous JBoss AS 5.1 - java, hibernate, jpa, jboss5.x, hibernate-search

J'essaie d'intégrer Hibernate Search dans un seulParmi les projets sur lesquels je travaille actuellement, la première étape consiste assez simplement à indexer toutes les entités existantes avec Hibernate Search (qui utilise Lucene sous le capot). De nombreuses tables mappées sur des entités du modèle de domaine contiennent: beaucoup d’enregistrements (> 1 million) et j’utilise une technique de pagination simple pour les scinder en unités plus petites. Cependant, je "rencontre une fuite de mémoire lors de l'indexation des entités. Voici mon code:

@Service(objectName = "LISA-Admin:service=HibernateSearch")
@Depends({"LISA-automaticStarters:service=CronJobs", "LISA-automaticStarters:service=InstallEntityManagerToPersistenceMBean"})
public class HibernateSearchMBeanImpl implements HibernateSearchMBean {
private static final int PAGE_SIZE = 1000;

private static final Logger LOGGER = LoggerFactory.getLogger(HibernateSearchMBeanImpl.class);

@PersistenceContext(unitName = "Core")
private EntityManager em;

@Override
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void init() {
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);

Session s = (Session) em.getDelegate();
SessionFactory sf = s.getSessionFactory();
Map<String, EntityPersister> classMetadata = sf.getAllClassMetadata();

for (String key : classMetadata.keySet()) {
LOGGER.info("Class: " + key + "nEntity name: " + classMetadata.get(key).getEntityName());

Class entityClass = classMetadata.get(key).getMappedClass(EntityMode.POJO);
LOGGER.info("Class: " + entityClass.getCanonicalName());

if (entityClass != null && entityClass.getAnnotation(Indexed.class) != null) {
index(fullTextEntityManager, entityClass, classMetadata.get(key).getEntityName());
}
}
}

@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void index(FullTextEntityManager pFullTextEntityManager, Class entityClass, String entityName) {
LOGGER.info("Class " + entityClass.getCanonicalName() + " is indexed by hibernate search");

int currentResult = 0;

Query tQuery = em.createQuery("select c from " + entityName + " as c order by oid asc");
tQuery.setFirstResult(currentResult);
tQuery.setMaxResults(PAGE_SIZE);

List entities;

do {
entities = tQuery.getResultList();
indexUnit(pFullTextEntityManager, entities);

currentResult += PAGE_SIZE;
tQuery.setFirstResult(currentResult);
} while (entities.size() == PAGE_SIZE);

LOGGER.info("Finished indexing for " + entityClass.getCanonicalName() + ", current result is " + currentResult);
}

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void indexUnit(FullTextEntityManager pFullTextEntityManager, List entities) {
for (Object object : entities) {
pFullTextEntityManager.index(object);
LOGGER.info("Indexed object with id " + ((BusinessObject)object).getOid());
}
}
}

C’est juste un simple MBean, dont init méthode que j’exécute manuellement via la console JMX de JBoss. Lorsque je surveille l'exécution de la méthode dans JVisualVM, je constate que l'utilisation de la mémoire augmente constamment jusqu'à ce que tout le tas soit consommé et, même si de nombreuses corbeilles se produisent, aucune mémoire ne se libère, ce qui me porte à croire que j'ai introduit une fuite de mémoire dans mon ordinateur. code. Cependant, je ne peux pas repérer le code incriminé, j’espère donc votre aide pour le localiser.

Le problème n'est certainement pas dans l'indexationelle-même, car je reçois la fuite même sans elle, alors je pense que je ne fais pas la pagination correctement. La seule référence aux entités que j’ai, cependant, est la liste entités, cela devrait être facilement récupéré après chaque itération de l'appel de boucle indexUnit.

Merci d'avance pour votre aide.

MODIFIER

Changer le code en

    List entities;

do {
Query tQuery = em.createQuery("select c from " + entityName + " as c order by oid asc");
tQuery.setFirstResult(currentResult);
tQuery.setMaxResults(PAGE_SIZE);

entities = tQuery.getResultList();
indexUnit(pFullTextEntityManager, entities);

currentResult += PAGE_SIZE;
tQuery.setFirstResult(currentResult);
} while (entities.size() == PAGE_SIZE);

atténué le problème. La fuite est toujours là, mais pas aussi grave qu’elle. Je suppose que la requête JPA elle-même a quelque chose d’inconvénient à conserver des références, mais ne sait pas.

Réponses:

0 pour la réponse № 1

Il semble que le EntityManager injecté soiten conservant une référence à toutes les entités renvoyées par votre requête. C’est un conteneur EM géré par conteneur, il doit donc être automatiquement fermé ou effacé à la fin de la transaction, mais vous effectuez toute une série de requêtes non transactionnelles.

Si vous allez simplement indexer les entités, vousvoudra peut-être appeler em.clear () à la fin de la boucle dans init (). Les entités seront détachées (EntityManager suivra les modifications qui leur ont été apportées), mais si elles "vont juste être GC", cela ne devrait pas poser de problème.


0 pour la réponse № 2

Je ne pense pas qu’il y ait une "fuite"; cependant, je le faisPensez que vous accumulez un grand nombre d’entités dans le contexte de persistance (oui, vous êtes en train de les recharger) et que vous finissez par manger toute la mémoire. Tu dois clear l'EM après chaque boucle (sans clear, la pagination n’aide pas). Quelque chose comme ça:

    do {
entities = tQuery.getResultList();
indexUnit(pFullTextEntityManager, entities);

pFullTextEntityManager.clear();

currentResult += PAGE_SIZE;
tQuery.setFirstResult(currentResult);
} while (entities.size() == PAGE_SIZE);

0 pour la réponse № 3

On dirait que cette question ne trouvera pas un vraiSolution. En fin de compte, je viens de déplacer le code d'indexation dans une application distincte - la fuite est toujours présente, mais cela n'a pas d'importance, car l'application est en cours d'exécution (avec un énorme tas) en dehors du conteneur critique .