/ / Speicherverlust bei paginierten JPA-Abfragen unter JBoss AS 5.1 - java, hibernate, jpa, jboss5.x, hibernate-search

Speicherverlust mit ausgelagerten JPA-Abfragen unter JBoss AS 5.1 - Java, Ruhezustand, jpa, jboss5.x, Ruhezustand-Suche

Ich versuche, die Hibernate-Suche in eine zu integrierenVon den Projekten, an denen ich gerade arbeite, ist der erste Schritt in einem solchen Unterfangen ziemlich einfach: Indizieren Sie alle vorhandenen Entitäten mit Hibernate Search (die Lucene unter der Haube verwendet). Viele der Entitäten im Domänenmodell zugeordneten Tabellen enthalten viele Aufzeichnungen (> 1 Million) und ich verwende die einfache Paginierungsmethode, um sie in kleinere Einheiten aufzuteilen. Beim Indizieren der Entitäten tritt jedoch ein Speicherleck auf. Hier ist mein 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());
}
}
}

Es ist nur eine einfache MBean, deren drin Die Methode wird manuell über die JMX-Konsole von JBoss ausgeführt. Wenn ich die Ausführung der Methode in der JVisualVM überwache, sehe ich, dass die Speichernutzung ständig zunimmt, bis der gesamte Heapspeicher verbraucht ist und obwohl viele Speicherbereinigungen vorkommen, wird kein Speicher freigegeben, der mich zu der Annahme führt, dass ich einen Speicherverlust in meine eingefügt habe Code. Ich kann jedoch den fehlerhaften Code nicht erkennen, deshalb hoffe ich auf Ihre Unterstützung bei der Suche.

Das Problem liegt sicherlich nicht in der Indexierungselbst, weil ich das Leck auch ohne bekomme, also denke ich, ich mache die Paginierung nicht richtig Entitäten, das sollte nach jeder Iteration des Aufrufens der Schleife leicht Müll sein indexUnit.

Vielen Dank im Voraus für Ihre Hilfe.

BEARBEITEN

Ändern Sie den Code in

    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);

das Problem gelöst. Das Leck ist immer noch da, aber nicht so schlimm wie es war. Ich schätze, die JPA-Abfrage selbst ist fehlerhaft, die Referenzen sollten nicht beibehalten werden, aber wer weiß.

Antworten:

0 für die Antwort № 1

Es sieht aus wie der eingespritzte EntityManagerFesthalten an einem Verweis auf alle Entitäten, die von Ihrer Abfrage zurückgegeben wurden. Es handelt sich um ein von einem Container verwaltetes EM, das am Ende einer Transaktion automatisch geschlossen oder gelöscht werden sollte.

Wenn Sie nur die Entitäten indizieren wollen, müssen SieVielleicht möchten Sie em.clear () am Ende der Schleife in init () aufrufen. Die Entitäten werden getrennt (der EntityManager verfolgt Änderungen, die an ihnen vorgenommen wurden), aber wenn sie einfach nur GC sind, sollte das kein Problem sein.


0 für die Antwort № 2

Ich glaube nicht, dass es ein "Leck" gibt, aber ich tue esIch denke, Sie sammeln eine große Anzahl von Entitäten im Persistenzkontext an (ja, Sie sind es, da Sie sie laden) und essen schließlich alle Speicher. Du musst clear die EM nach jeder Schleife (ohne clear, paging hilft nicht). Etwas wie das:

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

pFullTextEntityManager.clear();

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

0 für die Antwort № 3

Es scheint, als würde diese Frage nicht wirklich seinLösung. Am Ende habe ich gerade den Indexierungscode in eine separate App verschoben - das Leck ist immer noch da, aber das spielt keine Rolle, da die App außerhalb des kritischen Containers vollständig abgeschlossen ist (mit einem riesigen Heap) .