2010-04-28 8 views
15

मैं अपने एप्लिकेशन में 1 मिलियन रिकॉर्ड प्रोसेस कर रहा हूं, जिसे मैं एक MySQL डेटाबेस से पुनर्प्राप्त करता हूं। ऐसा करने के लिए मैं रिकॉर्ड प्राप्त करने के लिए लिंक का उपयोग कर रहा हूं और एक समय में 250 रिकॉर्ड्स को संसाधित करने के लिए .किप() और .टेक() का उपयोग कर रहा हूं। प्रत्येक पुनर्प्राप्त रिकॉर्ड के लिए मुझे 0 से 4 आइटम बनाने की आवश्यकता है, जिसे मैं डेटाबेस में जोड़ता हूं। तो कुल वस्तुओं की औसत राशि जो लगभग बनाई जानी है, लगभग 2 मिलियन है।बहुत सारी ऑब्जेक्ट्स बनाते समय स्मृति से बाहर C#

IQueryable<Object> objectCollection = dataContext.Repository<Object>(); 
int amountToSkip = 0; 
IList<Object> objects = objectCollection.Skip(amountToSkip).Take(250).ToList(); 
while (objects.Count != 0) 
     { 
      using (dataContext = new LinqToSqlContext(new DataContext())) 
      { 
       foreach (Object objectRecord in objects) 
       { 
        // Create 0 - 4 Random Items 
        for (int i = 0; i < Random.Next(0, 4); i++) 
        { 
         Item item = new Item(); 
         item.Id = Guid.NewGuid(); 
         item.Object = objectRecord.Id; 
         item.Created = DateTime.Now; 
         item.Changed = DateTime.Now; 
         dataContext.InsertOnSubmit(item); 
        } 
       } 
       dataContext.SubmitChanges(); 
      } 
      amountToSkip += 250; 
      objects = objectCollection.Skip(amountToSkip).Take(250).ToList(); 
     } 

अब आइटम बनाते समय समस्या उत्पन्न होती है। एप्लिकेशन चलाते समय (और डेटा कॉन्टेक्स्ट का उपयोग भी नहीं) स्मृति लगातार बढ़ती है। ऐसा लगता है कि वस्तुओं को कभी निपटान नहीं किया जा रहा है। क्या कोई ध्यान देता है कि मैं क्या गलत कर रहा हूं?

अग्रिम धन्यवाद!

+0

आप अपनी ऑब्जेक्ट को कैसे प्रारंभ करते हैं? –

+0

IQueryable ऑब्जेक्ट चयन = डेटा कॉन्टेक्स्ट। रिपोजिटरी (); – Bas

+0

ऑब्जेक्ट चयन पर फिर से शुरू करने के बजाय आप 250 के बैच क्यों लेते हैं? – Jens

उत्तर

7

ठीक है मैं सिर्फ मेरा है और हम एक साथी के साथ इस स्थिति चर्चा की है निम्नलिखित समाधान पर आ गया है जो काम करता है!

int amountToSkip = 0; 
var finished = false; 
while (!finished) 
{ 
     using (var dataContext = new LinqToSqlContext(new DataContext())) 
     { 
      var objects = dataContext.Repository<Object>().Skip(amountToSkip).Take(250).ToList(); 
      if (objects.Count == 0) 
       finished = true; 
      else 
      { 
       foreach (Object object in objects) 
       { 
        // Create 0 - 4 Random Items 
        for (int i = 0; i < Random.Next(0, 4); i++) 
        { 
         Item item = new Item(); 
         item.Id = Guid.NewGuid(); 
         item.Object = object.Id; 
         item.Created = DateTime.Now; 
         item.Changed = DateTime.Now; 
         dataContext.InsertOnSubmit(item); 
        } 
       } 
       dataContext.SubmitChanges(); 
      } 
      // Cumulate amountToSkip with processAmount so we don't go over the same Items again 
      amountToSkip += processAmount; 
     } 
} 
इस कार्यान्वयन के साथ

हम छोड़ें() निपटाने और (लो) कैश हर और इस तरह स्मृति रिसाव नहीं है!

2

मेरा सबसे अच्छा अनुमान मेमोरी लीक का कारण बनने के लिए IQueryable होगा। शायद टेक/छोड़ने के तरीकों के MySQL के लिए कोई उचित कार्यान्वयन नहीं है और यह स्मृति में पेजिंग कर रहा है? अजनबी चीजें हुई हैं, लेकिन आपका लूप ठीक दिखता है। सभी संदर्भों को दायरे से बाहर जाना चाहिए और कचरा इकट्ठा करना चाहिए ..

0

ठीक है हाँ।

तो उस लूप के अंत में आप अपनी सूची में 2 मिलियन आइटम रखने का प्रयास करेंगे, नहीं? मुझे लगता है कि जवाब छोटा है: कम आइटम स्टोर करें या अधिक मेमोरी प्राप्त करें।

- संपादित करें:

यह संभव मैं गलत इसे पढ़ लिया है मैं शायद संकलन और यह परीक्षण की आवश्यकता है, लेकिन मैं ऐसा नहीं कर सकते कि अब। मैं इसे यहां छोड़ दूंगा, लेकिन मैं गलत हो सकता हूं, मैंने निश्चित रूप से यह सुनिश्चित करने के लिए पर्याप्त रूप से पर्याप्त समीक्षा नहीं की है, फिर भी उत्तर उपयोगी साबित हो सकता है या नहीं। (Downvote से परखने के बाद, मुझे नहीं लगता है कि: पी)

+0

नहीं, उसके पास 2 मिलियन प्रविष्टियों वाला डेटाबेस है, उन्हें एक समय में 250 लेता है और फिर डेटाबेस में 4 नई उप-प्रविष्टियां जोड़ता है। स्मृति में किसी भी प्रकार की कोई सूची नहीं है .. प्रश्न पढ़ें .. – Tigraine

+0

@ टाइगर मुझे लगता है कि यह वह स्किप है जो उसे खराब कर रही है। वैसे भी, मेरा अनुमान है। –

+0

कैश, सूची ऑब्जेक्ट में चयन, बाधा है। यह स्वचालित रूप से – Bas

0

आप इस तरह पाश बाहर आइटम घोषित करने की कोशिश की है:

IQueryable<Object> objectCollection = dataContext.Repository<Object>(); 
int amountToSkip = 0; 
IList<Object> objects = objectCollection.Skip(amountToSkip).Take(250).ToList(); 
Item item = null; 
while (objects.Count != 0) 
     { 
      using (dataContext = new LinqToSqlContext(new DataContext())) 
      { 
       foreach (Object objectRecord in objects) 
       { 
        // Create 0 - 4 Random Items 
        for (int i = 0; i < Random.Next(0, 4); i++) 
        { 
         item = new Item(); 
         item.Id = Guid.NewGuid(); 
         item.Object = objectRecord.Id; 
         item.Created = DateTime.Now; 
         item.Changed = DateTime.Now; 
         dataContext.InsertOnSubmit(item); 
        } 
       } 
       dataContext.SubmitChanges(); 
      } 
      amountToSkip += 250; 
      objects = objectCollection.Skip(amountToSkip).Take(250).ToList(); 
     } 
+0

का निपटारा नहीं किया है, यह कोशिश की है, काम नहीं किया है। <मुझे लगता है, जैसे कि टिग्रेन ने कहा, यह IQueryable और टेक/छोड़ने के कारण है ... – Bas

5

अहह, अच्छी पुरानी InsertOnSubmit स्मृति रिसाव। LINQ से SQL का उपयोग करके बड़ी सीवीएस फ़ाइलों से डेटा लोड करने का प्रयास करते समय मैंने कई बार दीवार के खिलाफ अपना सिर लगाया और दीवार के खिलाफ अपना सिर लगाया। समस्या यह है कि SubmitChanges पर कॉल करने के बाद भी, DataContextInsertOnSubmit का उपयोग करके जोड़े गए सभी ऑब्जेक्ट्स को ट्रैक करना जारी रखता है। कुछ निश्चित ऑब्जेक्ट्स के बाद समाधान SubmitChanges पर है, फिर अगले बैच के लिए एक नया DataContext बनाएं। जब पुराना DataContext कचरा इकट्ठा किया जाता है, तो सभी डाले गए ऑब्जेक्ट्स जिन्हें ट्रैक किया जाता है (और अब आपको आवश्यकता नहीं है)।

"लेकिन प्रतीक्षा करें!" आप कहते हैं, "कई डेटाकॉन्टेक्स्ट बनाने और निपटाने के लिए एक बड़ा ओवरहेड होगा!"। खैर, नहीं, यदि आप एक डेटाबेस कनेक्शन बनाते हैं और इसे प्रत्येक DataContext कन्स्ट्रक्टर में पास करते हैं। इस तरह, डेटाबेस के लिए एक कनेक्शन पूरे बनाए रखा जाता है, और DataContext ऑब्जेक्ट अन्यथा हल्का वजन वाला ऑब्जेक्ट होता है जो एक छोटी कार्य इकाई का प्रतिनिधित्व करता है और इसे पूर्ण होने के बाद त्याग दिया जाना चाहिए (आपके उदाहरण में, रिकॉर्ड की एक निश्चित संख्या जमा करना)।

+0

एह मैंने अपने प्रश्न में कहा है कि जब भी मैं डेटाकॉन्टेक्स्ट का उपयोग इस रिसाव को नहीं कर रहा है, इसलिए यह InsertOnSubmit या SubmitChanges (मैंने पहले से ही इसका परीक्षण किया है) के लिए बाध्य नहीं है और एक उपयोग ब्लॉक में DataContext का उपयोग करने का सबसे अच्छा अभ्यास है। DataContextes lightweigth हैं और इसे बहुत से पुनर्निर्मित करने के लिए हैं (देखें: http://stackoverflow.com/questions/123057/how-do-i-avoid-a-memory-leak-with-linq-to-sql)। मैंने पहले ही सभी लेनदेन करने के लिए 1 डेटा कॉन्टेक्स्ट का उपयोग करने का प्रयास किया है, जो इससे भी बदतर था। – Bas

+0

आप जो कहते हैं उसे दोहरा रहे हैं - प्रत्येक छोटी कार्य इकाई के लिए एक नया डेटा कॉन्टेक्स्ट का उपयोग करें (बेशक 'कथन का उपयोग करके)। और आपने 'DataContext' के बिना अपने उदाहरण का परीक्षण कैसे किया? आपको 'ऑब्जेक्ट्स' संग्रह कहां से मिला? –

+0

क्षमा करें मेरा मतलब InsertOnSubmit और सबमिटChanges कॉल के बिना था;] मेरा बुरा। सबसे पहले मैंने यह भी सोचा कि InsertOnSubmit और SubmitChanges समस्या को ठीक करने और दूसरी रन करने के बाद समस्या थी, फिर भी मुझे रिसाव मिला। रिसाव छोड़ने और ले जाने के कारण है जो सभी पुनर्प्राप्त वस्तुओं को छूता है और कभी भी इसे चलाने के दौरान स्वचालित रूप से इसका निपटान नहीं करता है। तो आखिर में मेरे पास एक छिद्रित सूची में 2 मिलियन आइटम थे। – Bas