कचरा संग्रह केवल स्मृति तक ही क्यों सीमित है, अन्य संसाधन प्रकारों पर नहीं?


12

ऐसा लगता है कि लोग मैनुअल मेमोरी प्रबंधन से थक गए थे, इसलिए उन्होंने कचरा संग्रह का आविष्कार किया, और जीवन काफी अच्छा था। लेकिन हर दूसरे संसाधन प्रकारों के बारे में क्या? फ़ाइल डिस्क्रिप्टर, सॉकेट या यहां तक ​​कि उपयोगकर्ता ने डेटाबेस कनेक्शन जैसे डेटा बनाया है?

यह एक भोले सवाल की तरह लगता है, लेकिन मुझे ऐसा कोई स्थान नहीं मिला, जहां किसी ने भी पूछा हो। आइए फाइल डिस्क्रिप्टर पर विचार करें। कहते हैं कि एक कार्यक्रम जानता है कि यह शुरू होने पर केवल 4000 एफडी उपलब्ध होने की अनुमति होगी। जब भी यह एक ऑपरेशन करता है जो एक फाइल डिस्क्रिप्टर को खोलेगा, अगर यह होगा तो क्या होगा

  1. यह सुनिश्चित करने के लिए जांचें कि यह बाहर चलाने के बारे में नहीं है।
  2. यदि यह है, तो कचरा कलेक्टर को ट्रिगर करें, जो मेमोरी का एक गुच्छा मुक्त करेगा।
  3. यदि कुछ मेमोरी ने फाइल डिस्क्रिप्टर में संदर्भ को मुक्त कर दिया है, तो उन्हें तुरंत बंद कर दें। यह जानता है कि स्मृति एक संसाधन से संबंधित थी क्योंकि उस संसाधन से बंधी मेमोरी को एक 'फ़ाइल डिस्क्रिप्टर रजिस्ट्री' में पंजीकृत किया गया था, बेहतर कार्यकाल की कमी के कारण, जब इसे पहली बार खोला गया था।
  4. एक नया फ़ाइल डिस्क्रिप्टर खोलें, इसे नई मेमोरी में कॉपी करें, उस मेमोरी लोकेशन को 'फाइल डिस्क्रिप्टर रजिस्ट्री' में पंजीकृत करें और इसे उपयोगकर्ता को लौटा दें।

इसलिए संसाधन को तुरंत मुक्त नहीं किया जाएगा, लेकिन जब भी जीसी चलेगा, जो कि संसाधन से बाहर निकलने के बारे में है, तो यह पूरी तरह से उपयोग नहीं किया जा रहा है, इसके तुरंत बाद इसे मुक्त कर दिया जाएगा।

और ऐसा लगता है कि कई उपयोगकर्ता परिभाषित संसाधन सफाई मुद्दों के लिए पर्याप्त होगा। मैं यहां एक एकल टिप्पणी खोजने में कामयाब रहा, जो C ++ में इसी तरह के एक थ्रेड के साथ सफाई करने वाला संदर्भ है जिसमें एक संसाधन का संदर्भ होता है और इसे साफ करता है जब केवल एक ही संदर्भ शेष होता है (सफाई थ्रेड से), लेकिन मैं कर सकता हूं ' टी यह पुस्तकालय या किसी भी मौजूदा भाषा का हिस्सा होने के किसी भी सबूत का पता लगाएं।

जवाबों:


4

जीसी एक अनुमानित और आरक्षित संसाधन से संबंधित है। वीएम का इस पर कुल नियंत्रण है और किस पर और किस समय सृजन होता है, इस पर कुल नियंत्रण है। यहां कीवर्ड "आरक्षित" और "कुल नियंत्रण" हैं। हैंडल ओएस द्वारा आवंटित किए गए हैं, और संकेत हैं ... प्रबंधित स्थान के बाहर आवंटित संसाधनों के लिए अच्छी तरह से संकेत। इस वजह से, हैंडल और पॉइंटर्स प्रबंधित कोड के अंदर उपयोग करने के लिए प्रतिबंधित नहीं हैं। उनका उपयोग किया जा सकता है - और अक्सर - प्रबंधित और अप्रबंधित कोड द्वारा एक ही प्रक्रिया पर चल रहे हैं।

एक "रिसोर्स कलेक्टर" यह सत्यापित करने में सक्षम होगा कि हैंडल / पॉइंटर का उपयोग किसी प्रबंधित स्थान के भीतर किया जा रहा है या नहीं, लेकिन यह परिभाषा से अनभिज्ञ है कि यह मेमोरी स्पेस के बाहर क्या हो रहा है (और, चीजों को खराब करने के लिए कुछ हैंडल का उपयोग किया जा सकता है) प्रक्रिया सीमाओं के पार)।

एक व्यावहारिक उदाहरण .NET CLR है। कोई कोड लिखने के लिए फ्लेवर्ड C ++ का उपयोग कर सकता है जो प्रबंधित और अप्रबंधित मेमोरी स्पेस दोनों के साथ काम करता है; प्रबंधित और अप्रबंधित कोड के बीच हैंडल, पॉइंटर्स और संदर्भों को पास किया जा सकता है। अनवांटेड कोड को विशेष निर्माणों / प्रकारों का उपयोग करना चाहिए ताकि CLR को प्रबंधित संसाधनों के लिए किए जा रहे संदर्भों पर नज़र रखने की अनुमति मिल सके। लेकिन यह सबसे अच्छा यह कर सकता है। यह हैंडल और पॉइंटर्स के साथ ऐसा नहीं कर सकता है, और कहा कि संसाधन कलेक्टर को नहीं पता होगा कि क्या किसी विशेष हैंडल या पॉइंटर को जारी करना ठीक है।

संपादित करें: .NET CLR के बारे में, मैं .NET प्लेटफॉर्म के साथ C ++ डेवलपमेंट के साथ अनुभवी नहीं हूं। शायद वहाँ विशेष तंत्र हैं जो सीएलआर को प्रबंधित और अप्रबंधित कोड के बीच हैंडल / पॉइंटर्स के संदर्भों पर नज़र रखने की अनुमति देता है। अगर ऐसा है तो सीएलआर उन संसाधनों के जीवनकाल का ध्यान रख सकता है और उन्हें तब जारी कर सकता है जब उनके लिए सभी संदर्भ साफ हो जाएं (ठीक है, कम से कम कुछ परिदृश्यों में यह हो सकता है)। किसी भी तरह से, सर्वोत्तम प्रथाएं तय करती हैं कि हैंडल (विशेष रूप से फाइलों की ओर इशारा करने वाले) और पॉइंटर्स को जल्द से जल्द जारी किया जाए, जिसकी उन्हें जरूरत नहीं है। एक संसाधन कलेक्टर इसका अनुपालन नहीं करेगा, यह एक और कारण नहीं है।

संपादित 2: यह CLR / JVM / VMs-in-in पर अपेक्षाकृत तुच्छ है, किसी विशेष हैंडल को मुक्त करने के लिए कुछ कोड लिखने के लिए यदि यह केवल प्रबंधित स्थान के अंदर उपयोग किया जाता है। .NET में कुछ इस तरह होगा:

// This class offends many best practices, but it would do the job.
public class AutoReleaseFileHandle {
    // keeps track of how many instances of this class is in memory
    private static int _toBeReleased = 0;

    // the threshold when a garbage collection should be forced
    private const int MAX_FILES = 100;

    public AutoReleaseFileHandle(FileStream fileStream) {
       // Force garbage collection if max files are reached.
       if (_toBeReleased >= MAX_FILES) {
          GC.Collect();
       }
       // increment counter
       Interlocked.Increment(ref _toBeReleased);
       FileStream = fileStream;
    }

    public FileStream { get; private set; }

    private void ReleaseFileStream(FileStream fs) {
       // decrement counter
       Interlocked.Decrement(ref _toBeReleased);
       FileStream.Close();
       FileStream.Dispose();
       FileStream = null;
    }

    // Close and Dispose the Stream when this class is collected by the GC.
    ~AutoReleaseFileHandle() {
       ReleaseFileStream(FileStream);
    }

    // because it's .NET this class should also implement IDisposable
    // to allow the user to dispose the resources imperatively if s/he wants 
    // to.
    private bool _disposed = false;
    public void Dispose() {
      if (_disposed) {
        return;
      }
      _disposed = true;
      // tells GC to not call the finalizer for this instance.
      GC.SupressFinalizer(this);

      ReleaseFileStream(FileStream);
    }
}

// use it
// for it to work, fs.Dispose() should not be called directly,
var fs = File.Open("path/to/file"); 
var autoRelease = new AutoReleaseFileHandle(fs);

3

यह उन कारणों में से एक प्रतीत होता है जो कचरा बीनने वालों के साथ भाषा फाइनल करते हैं। फाइनलर्स का इरादा एक प्रोग्रामर को कचरा संग्रहण के दौरान किसी ऑब्जेक्ट के संसाधनों को साफ करने की अनुमति देना है। फाइनल के साथ बड़ी समस्या यह है कि वे चलाने की गारंटी नहीं हैं।

यहाँ फाइनल का उपयोग करने पर एक बहुत अच्छा लेखन है:

ऑब्जेक्ट फाइनल और क्लीनअप

वास्तव में यह विशेष रूप से एक उदाहरण के रूप में फ़ाइल डिस्क्रिप्टर का उपयोग करता है। आपको ऐसे संसाधन को स्वयं साफ करना सुनिश्चित करना चाहिए, लेकिन एक ऐसा तंत्र है जो एमईई संसाधनों को पुनर्स्थापित करता है जो ठीक से जारी नहीं किए गए थे।


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

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

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

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

3

इस प्रकार के संसाधनों को प्रबंधित करने में मदद करने के लिए कई प्रोग्रामिंग तकनीकें हैं।

  • C ++ प्रोग्रामर अक्सर संसाधन अधिग्रहण नामक एक पैटर्न का उपयोग करते हैं , प्रारंभिक या संक्षिप्त रूप से RAII है। यह पैटर्न यह सुनिश्चित करता है कि जब कोई वस्तु जो संसाधनों पर धारण करती है, वह दायरे से बाहर हो जाती है, तो यह उन संसाधनों को बंद कर देगा, जिन पर वह चल रहा था। यह तब मददगार होता है जब ऑब्जेक्ट का जीवनकाल कार्यक्रम में किसी विशेष दायरे से मेल खाता हो (जैसे, यह उस समय से मेल खाता है जब स्टैक पर एक विशेष स्टैक फ्रेम मौजूद होता है), इसलिए यह उन ऑब्जेक्ट्स के लिए मददगार होता है जिन्हें स्थानीय चर (पॉइंटर) द्वारा इंगित किया जाता है ढेर पर संग्रहीत चर), लेकिन ढेर पर संग्रहीत पॉइंटर्स द्वारा इंगित की जाने वाली वस्तुओं के लिए इतना उपयोगी नहीं है।

  • जावा, सी #, और कई अन्य भाषाएं एक ऐसी विधि को निर्दिष्ट करने का एक तरीका प्रदान करती हैं जिसे तब लागू किया जाएगा जब कोई वस्तु अब नहीं रहती है और कचरा संग्रहकर्ता द्वारा एकत्र की जाने वाली है। देखें, उदाहरण के लिए, फाइनल dispose(), और अन्य। विचार यह है कि प्रोग्रामर इस तरह की विधि को लागू कर सकता है ताकि यह कचरा कलेक्टर द्वारा ऑब्जेक्ट को मुक्त करने से पहले संसाधन को स्पष्ट रूप से बंद कर देगा। हालाँकि, इन दृष्टिकोणों में कुछ मुद्दे हैं, जिन्हें आप अन्यत्र पढ़ सकते हैं; उदाहरण के लिए, कचरा संग्रहकर्ता वस्तु को तब तक एकत्र नहीं कर सकता है जब तक आप चाहें।

  • C # और अन्य भाषाएँ एक ऐसा usingकीवर्ड प्रदान करती हैं जो यह सुनिश्चित करने में मदद करता है कि संसाधनों को बंद कर दिया गया है क्योंकि उनकी अब आवश्यकता नहीं है (इसलिए आप फ़ाइल डिस्क्रिप्टर या अन्य संसाधन को बंद करना न भूलें)। यह अक्सर कचरे के संग्रहकर्ता पर भरोसा करने से बेहतर है कि यह पता चले कि वस्तु अब जीवित नहीं है। देखें, जैसे, https://stackoverflow.com/q/75401/781723 । यहाँ सामान्य शब्द एक प्रबंधित संसाधन है । यह धारणा RAII और फाइनलर्स पर बनती है, उन पर कुछ तरीकों से सुधार होता है।


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

2

सभी मेमोरी बराबर है, अगर मैं 1K के लिए पूछता हूं, तो मुझे परवाह नहीं है कि पता स्थान 1K कहां से आता है।

जब मैं फ़ाइल हैंडल के लिए पूछता हूं, तो मैं उस फ़ाइल को हैंडल करना चाहता हूं जिसे मैं खोलना चाहता हूं। फ़ाइल पर फ़ाइल हैंडल खुला होना, अक्सर अन्य प्रक्रियाओं, या मशीन द्वारा फ़ाइल तक पहुंच को अवरुद्ध करता है।

इसलिए फ़ाइल हैंडल को आवश्यक नहीं होने पर बंद कर दिया जाना चाहिए, अन्यथा वे फ़ाइल तक अन्य पहुंच को अवरुद्ध करते हैं, लेकिन स्मृति को केवल तभी पुनः प्राप्त करने की आवश्यकता होती है जब आप इससे बाहर निकलना शुरू करते हैं।

जीसी पास चलाना महंगा है और केवल "जरूरत पड़ने पर" किया जाता है, यह अनुमान लगाना संभव नहीं है कि जब एथेर प्रक्रिया को एक फाइल हैंडल की आवश्यकता होगी जो आपकी प्रक्रिया अब उपयोग नहीं कर सकती है, लेकिन अभी भी खुला है।


आपका उत्तर वास्तविक कुंजी को हिट करता है: मेमोरी फंज़ेबल है, और अधिकांश सिस्टम में पर्याप्त है कि इसे विशेष रूप से जल्दी से पुनः प्राप्त करने की आवश्यकता नहीं है। इसके विपरीत, यदि कोई प्रोग्राम किसी फ़ाइल तक अनन्य पहुँच प्राप्त करता है, तो ब्रह्मांड में हर जगह किसी भी अन्य प्रोग्राम को ब्लॉक कर देगा, जिसे उस फ़ाइल का उपयोग करने की आवश्यकता हो सकती है, चाहे कितनी भी अन्य फाइलें मौजूद हों।
सुपरैट

0

मैं इस कारण का अनुमान लगाऊंगा कि अन्य संसाधनों के लिए बहुत अधिक संपर्क क्यों नहीं किया गया है, यह ठीक है क्योंकि अधिकांश अन्य संसाधनों को जल्द से जल्द किसी के लिए भी पुन: उपयोग करने के लिए जारी किया जाना पसंद किया जाता है।

ध्यान दें, निश्चित रूप से, आपका उदाहरण मौजूदा जीसी तकनीकों के साथ "कमजोर" फ़ाइल विवरणकों का उपयोग करके प्रदान किया जा सकता है।


0

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.