Dépassement de mémoire lors de la lecture de grandes quantités de données à l'aide d'hibernate
J'ai besoin d'exporter une grande quantité de données provenant de la base de données. Voici les classes que représente mes données:
public class Product{
...
@OneToMany
@JoinColumn(name = "product_id")
@Cascade({SAVE_UPDATE, DELETE_ORPHAN})
List<ProductHtmlSource> htmlSources = new ArrayList<ProductHtmlSource>();
...
}
ProductHtmlSource
- contient la chaîne de caractères à l'intérieur de laquelle j'ai réellement besoin d'exporter.
Depuis la taille des données exportées est plus grande que la mémoire JVM je suis en train de lire mes données par morceaux. Comme ceci:
final int batchSize = 1000;
for (int i = 0; i < 50; i++) {
ScrollableResults iterator = getProductIterator(batchSize * i, batchSize * (i + 1));
while (iterator.getScrollableResults().next()) {
Product product = (Product) iterator.getScrollableResults().get(0);
List<String> htmls = product.getHtmlSources();
<some processing>
}
}
Code de getProductIterator
:
public ScrollableResults getProductIterator(int offset, int limit) {
Session session = getSession(true);
session.setCacheMode(CacheMode.IGNORE);
ScrollableResults iterator = session
.createCriteria(Product.class)
.add(Restrictions.eq("status", Product.Status.DONE))
.setFirstResult(offset)
.setMaxResults(limit)
.scroll(ScrollMode.FORWARD_ONLY);
session.flush();
session.clear();
return iterator;
}
Le problème est que, en dépit de je de compensation de la session après la lecture de chaque segment de données Product
objets s'accumule quelque part et que je suis obtenir exception OutOfMemory. Le problème n'est pas dans le bloc de traitement de code, même sans, je reçois une erreur de la mémoire. La taille de lot n'est pas non plus un problème depuis 1000 objets facilement s'asseoir dans la mémoire.
Profiler a montré que les objets s'accumule dans org.hibernate.engine.StatefulPersistenceContext
classe.
La stacktrace:
Caused by: java.lang.OutOfMemoryError: Java heap space
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:99)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:518)
at java.lang.StringBuffer.append(StringBuffer.java:307)
at org.hibernate.type.TextType.get(TextType.java:41)
at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:163)
at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:154)
at org.hibernate.type.AbstractType.hydrate(AbstractType.java:81)
at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2101)
at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1380)
at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1308)
at org.hibernate.loader.Loader.getRow(Loader.java:1206)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:580)
at org.hibernate.loader.Loader.doQuery(Loader.java:701)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
at org.hibernate.loader.Loader.loadCollection(Loader.java:1994)
at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.java:36)
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:565)
at org.hibernate.event.def.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:63)
at org.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:1716)
at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:344)
at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:109)
at org.hibernate.collection.PersistentBag.size(PersistentBag.java:225)
**at com.rivalwatch.plum.model.Product.getHtmlSource(Product.java:76)
at com.rivalwatch.plum.model.Product.getHtmlSourceText(Product.java:80)
at com.rivalwatch.plum.readers.AbstractDataReader.getData(AbstractDataReader.java:64)**
OriginalL'auteur Vladimir | 2010-02-11
Vous devez vous connecter pour publier un commentaire.
Il semble que vous appelez getProductIterator() avec le début et la fin de la rangée des chiffres, tandis que getProductIterator() s'attend à la ligne de départ et un nombre de lignes. En tant que votre "limite supérieure" se fait plus forte, vous êtes de lire des données en gros morceaux. Je pense que tu veux dire passer batchSize comme deuxième argument getProductIterator().
OriginalL'auteur KeithL
Pas une réponse directe, mais pour ce genre de manipulation de données, je voudrais utiliser l'interface statelesssession n'.
OriginalL'auteur Pascal Thivent
KeithL est à droite - vous êtes de passage toujours plus de limite. Mais la rupture de cette façon ne fait pas de sens de toute façon. Le point de l'ensemble d'un curseur de défilement est que vous traitez une ligne à la fois, alors il n'y a pas besoin de le casser en morceaux. La taille de l'extraction réduit les voyages à la base de données sur le coût de l'utilisation de plus de mémoire. La tendance générale devrait être:
Cela dit, l'erreur est getHtmlSources de sorte que le problème peut être complètement étranger à la session/curseur de défilement/question. Si ces chaînes html sont énormes et ils sont référencés tout le temps, vous pouvez juste être à cours de mémoire contiguë.
Btw, je ne vois pas getScrollableResults méthode sur ScrollableResults.
Gab est correct. J'ai mis à jour la réponse à réfléchir.
OriginalL'auteur Brian Deterling
Au risque de paraître stupide - avez-vous envisagé de faire cela d'une autre façon?
Personnellement, je voudrais éviter de faire du traitement par lot qui "loin" de la base de données. Je ne sais pas ce que la base de données que vous utilisez, mais il n'y a habituellement un mécanisme permettant de tirer un ensemble de données de la base de données & dans un fichier, même si elle implique modérément simple manipulation sur le moyen de sortir. Procédures stockées, spécifique à l'exportation des services publics. Enquêter sur quoi d'autre est disponible auprès de votre fournisseur de base de données.
OriginalL'auteur mcottle
Vous pouvez poster l'Exception stacktrace?
Il peut être résolu en passant adapté options JVM pour GC.
Je pense que c'est lié - Java StringBuilder surcharge énorme.
Regarde à partir de la StackTrace qu'une très grande Chaîne est en cours de création et provoquant l'exception.
OriginalL'auteur Padmarag