2010-02-11 11 views
5

का उपयोग कर डेटा की बड़ी मात्रा में पढ़ने पर मुझे डेटाबेस से बड़ी मात्रा में डेटा निर्यात करने की आवश्यकता है। यहाँ वर्गों है मेरी डेटा का प्रतिनिधित्व करता है कि:आउटऑफमेमरी हाइबरनेट

public class Product{ 
... 

    @OneToMany 
    @JoinColumn(name = "product_id") 
    @Cascade({SAVE_UPDATE, DELETE_ORPHAN}) 
    List<ProductHtmlSource> htmlSources = new ArrayList<ProductHtmlSource>(); 

... }

ProductHtmlSource - बड़ा स्ट्रिंग जो अंदर मैं वास्तव में निर्यात करने के लिए आवश्यकता होती है।

चूंकि निर्यात किए गए डेटा का आकार JVM मेमोरी से बड़ा है, इसलिए मैं अपने डेटा को टुकड़ों से पढ़ रहा हूं। इस तरह:

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> 
    } 

}

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

समस्या यह है कि मैं एक डेटा हिस्सा के Product वस्तुओं को पढ़ने के बाद सत्र को साफ करने के बावजूद कहीं जम जाता है और मैं कर रहा हूँ OutOfMemory अपवाद प्राप्त करें। समस्या कोड के ब्लॉक को संसाधित करने में भी नहीं है, इसके बावजूद मुझे स्मृति त्रुटि मिलती है। बैच का आकार भी एक समस्या नहीं है क्योंकि 1000 ऑब्जेक्ट्स आसानी से स्मृति में बैठते हैं।

प्रोफाइलर ने दिखाया कि वस्तुओं org.hibernate.engine.StatefulPersistenceContext कक्षा में जमा हो जाती है।

स्टैकट्रेस: ​​

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

पोस्ट किया गया stacktrace लेकिन मुझे नहीं लगता कि जीसी की ट्यूनिंग मदद करेगा। मैंने System.gc() की कोशिश की; नए बैच पढ़ने से पहले स्मृति अभी भी बहती है। – Vladimir

उत्तर

4

ऐसा लगता है कि आप getProductIterator() को शुरुआती और समाप्ति पंक्ति संख्याओं के साथ कॉल कर रहे हैं, जबकि getProductIterator() प्रारंभिक पंक्ति और पंक्ति गणना की अपेक्षा कर रहा है। चूंकि आपकी "ऊपरी सीमा" अधिक हो जाती है, आप बड़े हिस्से में डेटा पढ़ रहे हैं। मुझे लगता है कि आप प्रोडक्टइटरेटर() प्राप्त करने के लिए दूसरे तर्क के रूप में बैच आकार को पास करना चाहते हैं।

0

आप पोस्ट कर सकते हैं अपवाद स्टैकट्रेस? जीसी के लिए उपयुक्त जेवीएम विकल्पों को पारित करके हल किया जा सकता है।

मुझे लगता है कि यह संबंधित है - Java StringBuilder huge overhead

स्टैकट्रेस से दिखता है कि एक बहुत बड़ी स्ट्रिंग बनाई जा रही है और अपवाद का कारण बन रहा है।

+0

क्या आपने LOB में स्टोर करने और आउटपुट के लिए स्ट्रीम का उपयोग करने का प्रयास किया है? – Padmarag

1

बेवकूफ दिखने के जोखिम पर - क्या आपने यह एक और तरीका करने पर विचार किया है?

व्यक्तिगत रूप से मैं बैच प्रसंस्करण करने से बचूंगा जो डेटाबेस से "बहुत दूर" है। मुझे नहीं पता कि आप किस डेटाबेस का उपयोग कर रहे हैं लेकिन डेटाबेस में & डेटाबेस से डेटासेट को प्रभावी रूप से खींचने के लिए एक तंत्र है, भले ही इसमें रास्ते में मामूली सरल हेरफेर शामिल हो। संग्रहीत प्रक्रियाओं, विशिष्ट निर्यात उपयोगिताओं। जांचें कि आपके डेटाबेस विक्रेता से और क्या उपलब्ध है।

2

प्रत्यक्ष उत्तर नहीं है लेकिन इस तरह के डेटा मैनिपुलेशन के लिए, मैं the StatelessSession interface का उपयोग करूंगा।

2

कीथल सही है - आप लगातार बढ़ती सीमा पारित कर रहे हैं। लेकिन इसे इस तरह तोड़ना वैसे भी समझ में नहीं आता है। स्क्रॉल कर्सर का पूरा बिंदु यह है कि आप एक समय में एक पंक्ति को संसाधित करते हैं, इसलिए इसे खंडों में तोड़ने की कोई आवश्यकता नहीं है। Fetch आकार अधिक स्मृति का उपयोग करने की लागत पर डेटाबेस के लिए यात्रा को कम कर देता है।सामान्य पद्धति होनी चाहिए:

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 
} 

जिसके अनुसार, त्रुटि getHtmlSources तो समस्या पूरी तरह से सत्र/कर्सर/पुस्तक मुद्दा से संबंधित नहीं हो सकते हैं। यदि वे HTML स्ट्रिंग बहुत बड़ी हैं और उन्हें पूरे समय संदर्भित किया जा रहा है, तो आप केवल संगत स्मृति से बाहर हो सकते हैं।

बीटीडब्ल्यू, मुझे स्क्रॉल करने योग्य रीसेट्स पर getScrollableResults विधि नहीं दिखाई दे रही है।

+0

"session.evict (p); // ऊपर दिए गए कैश मोड को सेट करने का विकल्प" यह कथन सिर्फ झूठा है, कैश मोड चिंता L2 और क्वेरी कैश सत्र नहीं है। एक बेदखल या स्पष्ट बयान अभी भी अनिवार्य है। – Gab

+0

गैब सही है। मैंने इसे प्रतिबिंबित करने के लिए उत्तर अपडेट किया। –

संबंधित मुद्दे