2013-03-28 5 views
5

मैं कुछ परीक्षण चला रहा था, यह देखने के लिए कि मेरा लॉगिंग कैसे करेगी File.AppendAllText करने के बजाय मैं पहले मेमोरी स्ट्रीम को लिखूंगा और फिर फ़ाइल में कॉपी करूंगा। तो, बस देखने के लिए कितनी तेजी से स्मृति ऑपरेशन है मैं इस किया था ..मुझे 700 एमबी रैम मुक्त होने पर भी सिस्टम.ऑटऑफ मेमरी अपवाद क्यों मिलता है?

private void button1_Click(object sender, EventArgs e) 
    { 
     using (var memFile = new System.IO.MemoryStream()) 
     { 
      using (var bw = new System.IO.BinaryWriter(memFile)) 
      { 
       for (int i = 0; i < Int32.MaxValue; i++) 
       { 
        bw.Write(i.ToString() + Environment.NewLine); 
       } 
       bw.Flush(); 
      } 
      memFile.CopyTo(new System.IO.FileStream(System.IO.Path.Combine("C", "memWriteWithBinaryTest.log"), System.IO.FileMode.OpenOrCreate)); 
     } 
    } 

जब i पहुँच 25413324 मैं एक Exception of type 'System.OutOfMemoryException' was thrown. मिला भले ही मेरी Process Explorer कहता है कि मैं से मुक्त राम 700MB के बारे में है ??? अधिक वस्तुओं की खातिर बनाया जा रहा:

यहाँ स्क्रीन शॉट्स (सिर्फ मामले में)

प्रोसेस एक्सप्लोरर enter image description here

यहाँ WinForm

enter image description here

संपादित है कर रहे हैं ढेर पर, मैं bw.write को इस

पर फिर से लिखता हूं
bw.Write(i); 
+0

उत्तर के अनुसार, 'बाइनरीवाइटर' संख्या के स्ट्रिंग प्रस्तुति को नहीं लिखता है। यह बाइट प्रतिनिधित्व लिखेंगे। शायद आप उत्तरार्द्ध चाहते हैं, लेकिन मूल कोड से ऐसा नहीं दिखता है। – leppie

उत्तर

9

सबसे पहले, आप स्मृति से बाहर निकलते हैं क्योंकि आप इसे पर सीधे लिखने के बजाय MemoryStream में डेटा जमा करते हैं। सीधे FileStream का उपयोग करें और आपको बहुत अधिक RAM की आवश्यकता नहीं होगी (लेकिन आपको फ़ाइल को खोलना होगा)।

अप्रयुक्त भौतिक स्मृति की मात्रा इस अपवाद के लिए सीधे प्रासंगिक नहीं है, जैसा कि ध्वनि हो सकता है।

क्या मायने रखती है:

  • आप इस प्रक्रिया को 'वर्चुअल ऐड्रेस स्पेस
  • कि इस प्रणाली के लिए प्रतिबद्ध कुल रैम आकार + पृष्ठ फ़ाइल आकार से अधिक नहीं है में उपलब्ध स्मृति का एक सन्निहित हिस्सा है

जब आप आप कुछ रैम आवंटित करने के लिए विंडोज स्मृति प्रबंधक से पूछते हैं, यह नहीं है कि कितना है उपलब्ध जाँच करने की जरूरत है, लेकिन यह है कि कितना ने अन्य सभी प्रक्रियाओं के लिए उपलब्ध कराने के लिए का वादा किया। इस तरह के वादा करता है प्रतिबद्धताओं के माध्यम से किया जाता है। प्रतिबद्ध करें कुछ मेमोरी का अर्थ है कि मेमोरी मैनेजर ने आपको गारंटी दी है कि उपलब्ध होगा जब आप अंत में इसका उपयोग करेंगे।

तो, यह हो सकता है कि भौतिक RAM पूरी तरह से उपयोग हो, लेकिन आपका आवंटन अनुरोध अभी भी सफल हो गया है। क्यूं कर? क्योंकि पेज फ़ाइल में बहुत सी जगह उपलब्ध है। जब आप वास्तव में इस तरह के आवंटन के माध्यम से राम का उपयोग करना शुरू करते हैं, तो स्मृति प्रबंधक बस कुछ और पृष्ठ निकाल देगा। तो 0 भौतिक रैम! = आवंटन विफल हो जाएगा।

विपरीत भी हो सकता है; कुछ अप्रयुक्त भौतिक RAM होने के बावजूद एक आवंटन विफल हो सकता है। आपकी प्रक्रिया तथाकथित आभासी पता स्थान के माध्यम से स्मृति को देखती है। जब आपकी प्रक्रिया 0x12340000 पते पर स्मृति पढ़ती है, तो यह एक आभासी पता है। यह 0x78650000 पर रैम पर मैप कर सकता है, या 0x000000AB12340000 (64-बिट ओएस पर 32-बिट प्रक्रिया चला रहा है) पर, यह उस पृष्ठ को इंगित कर सकता है जो केवल पृष्ठ फ़ाइल में मौजूद है, या यह किसी भी चीज़ पर भी इंगित नहीं कर सकता है।

जब आप संगत पते के साथ स्मृति का एक ब्लॉक आवंटित करना चाहते हैं, तो यह इस आभासी पता स्थान में है कि राम को संगत होने की आवश्यकता है। 32-बिट प्रक्रिया के लिए, आपको केवल 2 जीबी या 3 जीबी उपयोग योग्य पता स्थान मिलता है, इसलिए इसे मुफ्त में उपयोग करना बहुत कठिन नहीं है कि पर्याप्त भौतिक RAM और पर्याप्त दोनों होने के बावजूद पर्याप्त आकार का कोई संगत हिस्सा मौजूद नहीं है कुल अप्रयुक्त आभासी पता स्थान।

3

यह स्मृति विखंडन के कारण हो सकता है।

बड़ी वस्तुएं बड़े ऑब्जेक्ट ढेर पर जाती हैं और वे चीजों के लिए जगह बनाने के लिए चारों ओर स्थानांतरित नहीं होती हैं। यह विखंडन का कारण बन सकता है जहां आपके पास उपलब्ध स्मृति में अंतराल है, जो उपलब्ध स्मृति के किसी भी ब्लॉक से बड़े ऑब्जेक्ट आवंटित करने का प्रयास करते समय स्मृति से बाहर हो सकता है।

See here for more details

85,000 बाइट से बड़ा कोई भी वस्तु बड़े ऑब्जेक्ट ढेर पर रखी जाएगी, डबल्स के सरणी को छोड़कर, जिसके लिए दहलीज केवल 1000 युगल (या 8000 बाइट्स) है।

यह भी ध्यान दें कि 32-बिट .Net प्रोग्राम प्रति ऑब्जेक्ट अधिकतम 2 जीबी तक सीमित हैं और कुल मिलाकर 4 जीबी से कम (शायद ओएस के आधार पर 3 जीबी के रूप में कम)।

0

आपको फ़ाइल में टेक्स्ट लिखने के लिए BinaryWriter का उपयोग नहीं करना चाहिए। इसके बजाय TextWriter का उपयोग करें।

अब आप उपयोग कर रहे हैं:

for (int i = 0; i < Int32.MaxValue; i++)

यह लिखने (संख्या प्रतिनिधित्व और newline) प्रति कम से कम 3 बाइट्स लिखेंगे। टाइम्स कि Int32.MaxValue और आपको कम से कम 6 जीबी मेमोरी की आवश्यकता है जो पहले से ही देख रहा है कि आप इसे MemoryStream पर लिख रहे हैं।

अपने कोड पर आगे देखकर, आप किसी भी फाइल में MemoryStream लिखने जा रहे हैं।

for (int i = 0; i < int.MaxValue; i++) 
{ 
    File.AppendAllText("filename.log", i.ToString() + Environment.Newline); 
} 

या एक खुला TextWriter पर लिखें:: तो आप बस निम्न कर सकते हैं

TextWriter writer = File.AppendText("filename.log"); 

for (int i = 0; i < int.MaxValue; i++) 
{ 
    writer.WriteLine(i); 
} 

आप कुछ स्मृति बफर है, जो IMO प्रवेश के रूप में आप पिछले खो देंगे के लिए एक बुरा विचार है चाहते हैं

StreamWriter(string path, bool append, Encoding encoding, int bufferSize) 

और bufferSize के लिए एक 'बरा' नंबर पारित: एक दुर्घटना के दौरान लेखन की बिट, आप TextWriter बनाने निम्नलिखित का उपयोग कर सकते हैं। डिफ़ॉल्ट 1024 है।

प्रश्न का उत्तर देने के लिए, MemoryStream आकार बदलने के कारण आपको स्मृति अपवाद से बाहर निकलना पड़ता है और किसी बिंदु पर यह स्मृति में फिट होने के लिए बड़ा हो जाता है (जिसे किसी अन्य उत्तर में चर्चा की गई थी)।

+0

लॉगिंग के लिए बिल्कुल कोई सवाल नहीं है, मुझे Logger.Net आदि के बारे में पता है, लेकिन यह मामला सिर्फ एक साधारण लॉग था, मुझे यह जानने की भी आवश्यकता थी कि कितना प्रदर्शन बेहतर होगा (जिसका अर्थ है कि कितना कम समय खर्च होगा) अगर मैं पहले स्मृति के लिए लिखें और फिर फ़ाइल करने के लिए। – Razort4x

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