2010-02-11 30 views
5

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)** 
+0

Đã đă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

Trả lời

4

Dường như bạn đang gọi getProductIterator() với số hàng bắt đầu và kết thúc, trong khi getProductIterator() đang chờ hàng bắt đầu và số hàng. Khi "giới hạn trên" của bạn cao hơn, bạn đang đọc dữ liệu theo khối lớn hơn. Tôi nghĩ rằng bạn có nghĩa là để vượt qua batchSize như là đối số thứ hai để getProductIterator().

0

Bạn có thể gửi stacktrace ngoại lệ? Nó có thể được giải quyết bằng cách chuyển các tùy chọn JVM phù hợp cho GC.

Tôi nghĩ rằng điều này có liên quan - Java StringBuilder huge overhead.

Trông từ StackTrace mà một Chuỗi rất lớn đang được tạo và gây ra ngoại lệ.

+0

Bạn đã thử lưu trữ trong LOB và sử dụng Luồng cho đầu ra? – Padmarag

1

Có nguy cơ xuất hiện ngu ngốc - bạn có cân nhắc thực hiện theo cách khác không?

Cá nhân tôi sẽ tránh thực hiện xử lý hàng loạt "xa" từ cơ sở dữ liệu. Tôi không biết bạn đang sử dụng cơ sở dữ liệu nào nhưng thường có một cơ chế để kéo dữ liệu một cách hiệu quả ra khỏi cơ sở dữ liệu & vào một tệp ngay cả khi nó liên quan đến thao tác đơn giản vừa phải trên đường ra. Thủ tục lưu trữ, tiện ích xuất khẩu cụ thể. Điều tra những gì khác có sẵn từ nhà cung cấp cơ sở dữ liệu của bạn.

2

Không phải là câu trả lời trực tiếp nhưng đối với loại thao tác dữ liệu này, tôi sẽ sử dụng the StatelessSession interface.

2

KeithL đúng - bạn đang vượt qua giới hạn ngày càng tăng. Nhưng phá vỡ nó theo cách đó không có ý nghĩa anyway. Toàn bộ điểm của con trỏ cuộn là bạn xử lý một hàng tại một thời điểm để không cần phải chia nhỏ nó thành từng phần. Kích thước tìm nạp làm giảm các chuyến đi đến cơ sở dữ liệu với chi phí sử dụng nhiều bộ nhớ hơn.Mẫu chung phải là:

Query q = session.createCriteria(... no offset or limit ...); 
q.setCacheMode(CacheMode.IGNORE); // prevent query or second level caching 
q.setFetchSize(1000); // experiment with this to optimize performance vs. memory 
ScrollableResults iterator = query.scroll(ScrollMode.FORWARD_ONLY); 
while (iterator.next()) { 
    Product p = (Product)iterator.get(); 
    ... 
    session.evict(p); // required to keep objects from accumulating in the session 
} 

Điều đó nói rằng, lỗi là getHtmlSources do đó sự cố có thể hoàn toàn không liên quan đến vấn đề phiên/con trỏ/cuộn. Nếu những chuỗi html là rất lớn và chúng đang được tham chiếu toàn bộ thời gian, bạn có thể chỉ cần chạy ra khỏi bộ nhớ tiếp giáp.

Btw, tôi không thấy phương thức getScrollableResults trên ScrollableResults.

+0

"session.evict (p); // cách thay thế để đặt chế độ bộ nhớ cache ở trên" Tuyên bố này chỉ là sai, chế độ bộ nhớ cache liên quan đến L2 và bộ nhớ cache truy vấn không phải là phiên. Một tuyên bố trục xuất hoặc rõ ràng vẫn là bắt buộc. – Gab

+0

Gab là chính xác. Tôi đã cập nhật câu trả lời để phản ánh điều đó. –

Các vấn đề liên quan