OutofMemory عند قراءة كميات كبيرة من البيانات باستخدام السبات

StackOverflow https://stackoverflow.com/questions/2242999

سؤال

أحتاج إلى تصدير كمية كبيرة من البيانات من قاعدة البيانات. هنا هي الفصول التي تمثل بياناتي:

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 صف دراسي.

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)**
هل كانت مفيدة؟

المحلول

يبدو أنك تدعو GetProductiterator () مع أرقام الصف البداية والنهاية، في حين أن GetProDuctiteratorator () تتوقع صف البداية وعدد الصف. كما يحصل "الحد العلوي" أعلى، فأنت تقرأ البيانات في قطع أكبر. أعتقد أنك تعني تمرير الدفعات كحجة ثانية لتحديد المنتج ().

نصائح أخرى

ليس إجابة مباشرة ولكن لهذا النوع من معالجة البيانات، أود استخدامها واجهة deelessessessession.

Kithl هو الصحيح - أنت تمر بحد متزايد باستمرار. ولكن كسرها بهذه الطريقة لا معنى لها على أي حال. الهدف بأكمله مؤشر التمرير هو أنك تقوم بمعالجة صف واحد في كل مرة، لذلك ليس هناك حاجة لكسرها إلى قطع. حجم الجلب يقلل من الرحلات إلى قاعدة البيانات بتكلفة استخدام المزيد من الذاكرة. يجب أن يكون النمط العام:

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 هؤلاء ضخمة ويتم الرجوع إليها طوال الوقت، فقد تنفد فقط من الذاكرة المجاورة.

راجع للشغل، لا أرى طريقة GetScrollablesultsults على Scrollablesulesults.

في خطر ظهور غبي - هل فكرت في القيام بذلك بطريقة أخرى؟

شخصيا أود أن أتجنب القيام بمعالجة الدفعات التي "بعيدا" من قاعدة البيانات. لا أعرف ما قاعدة البيانات التي تستخدمها ولكن عادة ما تكون هناك آلية لسحب مجموعة بيانات بكفاءة من قاعدة البيانات وإلى ملف حتى إذا كان ينطوي على معالجة بسيطة معتدلة في الطريق. الإجراءات المخزنة، مرافق تصدير محددة. التحقيق في ما هو آخر متاح من بائع قاعدة البيانات الخاصة بك.

يمكنك نشر الاستثناء stacktrace؟ قد يتم حلها عن طريق تمرير خيارات JVM مناسبة ل GC.

أعتقد أن هذا مرتبط - جافا stringbuilder النفقات العامة الضخمة.

ينظر من StackTrace إلى أن سلسلة كبيرة جدا يتم إنشاؤها وتسبب الاستثناء.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top