Tôi cần xuất dữ liệu lớn từ cơ sở dữ liệu. Đây là lớp học mà đại diện cho dữ liệu của tôi:OutOfMemory khi đọc một lượng lớn dữ liệu bằng cách sử dụng hibernate
public class Product{
...
@OneToMany
@JoinColumn(name = "product_id")
@Cascade({SAVE_UPDATE, DELETE_ORPHAN})
List<ProductHtmlSource> htmlSources = new ArrayList<ProductHtmlSource>();
... }
ProductHtmlSource
- chứa chuỗi lớn bên trong mà tôi thực sự cần để xuất khẩu.
Vì kích thước dữ liệu được xuất lớn hơn bộ nhớ JVM Tôi đang đọc dữ liệu của mình theo khối. Như thế này:
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>
}
}
Mã của 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;
}
Vấn đề là mặc dù tôi thanh toán bù trừ phiên sau khi đọc từng đoạn dữ liệu Product
đối tượng tích tụ ở đâu đó và tôi nhận ngoại lệ OutOfMemory. Vấn đề không phải là trong xử lý khối mã ngay cả khi không có nó tôi nhận được lỗi bộ nhớ. Kích thước của lô cũng không phải là vấn đề vì 1000 đối tượng dễ dàng ngồi vào bộ nhớ.
Profiler cho thấy các đối tượng tích lũy trong lớp org.hibernate.engine.StatefulPersistenceContext
.
Các 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)**
Đã đăng stacktrace nhưng tôi không nghĩ rằng điều chỉnh gc sẽ giúp ích. Tôi đã thử System.gc(); trước khi đọc lô mới đặt bộ nhớ vẫn tràn. – Vladimir