2013-02-06 11 views
9

नीचे कोड पर विचार करें:सी # कचरा कलेक्टर तब तक स्मृति मुक्त करने की कोशिश क्यों नहीं करता जब तक कोई अनुरोध संतुष्ट न हो?

using System; 

namespace memoryEater 
{ 
    internal class Program 
    { 
     private static void Main(string[] args) 
     { 
      Console.WriteLine("alloc 1"); 
      var big1 = new BigObject(); 

      Console.WriteLine("alloc 2"); 
      var big2 = new BigObject(); 

      Console.WriteLine("null 1"); 
      big1 = null; 

      //GC.Collect(); 

      Console.WriteLine("alloc3"); 
      big1 = new BigObject(); 

      Console.WriteLine("done"); 
      Console.Read(); 
     } 
    } 

    public class BigObject 
    { 
     private const uint OneMeg = 1024 * 1024; 
     private static int _idCnt; 
     private readonly int _myId; 
     private byte[][] _bigArray; 

     public BigObject() 
     { 
      _myId = _idCnt++; 
      Console.WriteLine("BigObject {0} creating... ", _myId); 

      _bigArray = new byte[700][]; 

      for (int i = 0; i < 700; i++) 
      { 
       _bigArray[i] = new byte[OneMeg]; 
      } 

      for (int j = 0; j < 700; j++) 
      { 
       for (int i = 0; i < OneMeg; i++) 
       { 
        _bigArray[j][i] = (byte)i; 
       } 
      } 
      Console.WriteLine("done"); 
     } 

     ~BigObject() 
     { 
      Console.WriteLine("BigObject {0} finalised", _myId); 
     } 
    } 
} 

मैं एक वर्ग है, BigObject है, जो अपने निर्माता में एक 700MiB सरणी बनाता है, और एक को अंतिम रूप देने विधि है जो अन्य सांत्वना देने प्रिंट से कुछ नहीं करता है। मुख्य में, मैं इन दो वस्तुओं को मुक्त करता हूं, एक मुक्त करता हूं, और फिर एक तिहाई बना देता हूं।

यदि यह 32 बिट के लिए संकलित किया गया है (ताकि स्मृति को 2 गीगा तक सीमित किया जा सके), तो तीसरे बिगऑब्जेक्ट को बनाते समय स्मृति अपवाद को बाहर निकाला जाता है। ऐसा इसलिए है क्योंकि, जब तीसरे बार स्मृति का अनुरोध किया जाता है, तो अनुरोध संतुष्ट नहीं हो सकता है और इसलिए कचरा कलेक्टर चलता है। हालांकि, एकत्रित करने के लिए तैयार होने वाला पहला बिगऑब्जेक्ट, एक फाइनलर विधि है इसलिए एकत्रित होने की बजाय अंतिमकरण कतार पर रखा गया है और इसे अंतिम रूप दिया गया है। कचरा कलेक्टर तब रोकता है और अपवाद फेंक दिया जाता है। हालांकि, यदि जीसी.कोलेक्ट को कॉल अपूर्ण है, या अंतिम विधि हटा दी गई है, तो कोड ठीक हो जाएगा।

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

+1

समस्या finalizer में पक्ष प्रभाव के कारण होता है। ऐसा मत करो! – leppie

+2

मैं कुछ साल पहले भी आया और एक ब्लॉग पोस्ट लिखा। देखें: http://xacc.wordpress.com/2011/02/22/gc-suppressfinalize/ (टिप्पणियां भी देखें) – leppie

+0

दिलचस्प है, लेकिन कंसोल.WriteLine को अंतिमकर्ता से हटा दिया गया है, तो कोड अभी भी विफल रहता है। –

उत्तर

0

मुझे लगता है कि कचरा संग्रह के दौरान अंतिम बार निष्पादित करने का समय अपरिभाषित है। संसाधनों को किसी भी विशिष्ट समय पर रिलीज़ होने की गारंटी नहीं है (जब तक कि बंद विधि या निपटान विधि को कॉल न किया जाए)।, ऑर्डर करने वाले ऑर्डर को भी यादृच्छिक है ताकि आप किसी अन्य ऑब्जेक्ट पर एक फाइनलाइज़र प्राप्त कर सकें, जबकि आपका ऑब्जेक्ट उस के लिए इंतजार कर रहा है ।

2

जीसी काम करेगा और स्मृति को पुनः प्राप्त करने का प्रयास करेगा जब यह अनिश्चित है।

यदि आप big1 = null के बाद यह लाइन जोड़ते हैं। हालांकि आपको जीसी को इकट्ठा करने के लिए मजबूर होना चाहिए। इसकी सिफारिश नहीं की जाती है जबतक कि आप नहीं जानते कि आप क्या कर रहे हैं।

GC.Collect(); 
GC.WaitForPendingFinalizers(); 

Best Practice for Forcing Garbage Collection in C#

When should I use GC.SuppressFinalize()?

Garbage collection in .NET (generations)

+0

मैं समझता हूं कि यह बुरा अभ्यास है, यह समस्या का प्रदर्शन करने के लिए सिर्फ एक डेमो ऐप है। सवाल यह है कि अपवाद फेंकने से पहले कचरा कलेक्टर फाइनल और फ्री मेमोरी (जो आवंटन की अनुमति नहीं देगा) क्यों चलाता है? –

+0

@ सेनरइड http://stackoverflow.com/questions/10016541/garbage-collection-not-happening-even-when- इसे दबाया। अब यह स्पष्ट होना चाहिए कि जीसी स्वचालित रूप से क्यों नहीं हुआ। आप केवल LOH पर ऑब्जेक्ट्स बना रहे हैं (ध्यान रखें कि int प्रकार, जिस तरह से आपने उनका उपयोग किया है, उन्हें स्टैक पर आवंटित किया गया है और उन्हें एकत्रित करने की आवश्यकता नहीं है)। आप कभी पीढ़ी 0 भर नहीं रहे हैं, इसलिए एक जीसी कभी नहीं होता है। – adt

+0

बात यह है कि, एक जीसी चलाता है, और फ्रीड ऑब्जेक्ट का फाइनलर भी चलता है। (ध्यान दें कि एप्लिकेशन 32 बिट है, ताकि यह सुनिश्चित किया जा सके कि स्मृति के लिए पृष्ठ शुरू करने के बजाय हम 2 जीबी पर स्मृति से बाहर हो जाएं)। समस्या यह है कि जीसी को फाइनलर चलाने के लिए दो बार चलाने की ज़रूरत होती है और फिर वास्तव में स्मृति को मुक्त करने के लिए। –

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

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