कैसे जावा कचरा संग्रह परिपत्र संदर्भ के साथ काम करता है?


161

मेरी समझ से, जावा में कचरा संग्रह कुछ वस्तुओं को साफ कर देता है अगर कुछ और उस वस्तु की ओर इशारा नहीं करता है।

मेरा सवाल यह है कि अगर हमारे पास ऐसा कुछ हो तो क्या होगा:

class Node {
    public object value;
    public Node next;
    public Node(object o, Node n) { value = 0; next = n;}
}

//...some code
{
    Node a = new Node("a", null), 
         b = new Node("b", a), 
         c = new Node("c", b);
    a.next = c;
} //end of scope
//...other code

a, bऔर cकचरा एकत्र किया जाना चाहिए, लेकिन वे सभी अन्य वस्तुओं द्वारा संदर्भित किए जा रहे हैं।

जावा कचरा संग्रह इससे कैसे निपटता है? (या यह केवल एक स्मृति नाली है?)


1
देखें: stackoverflow.com/questions/407855/… , विशेष रूप से @gnud से दूसरा उत्तर।
सेठ

जवाबों:


161

जावा की GC वस्तुओं को "कचरा" मानती है यदि वे कचरा संग्रहण रूट पर शुरू होने वाली श्रृंखला के माध्यम से नहीं पहुंच पाती हैं, तो इन वस्तुओं को एकत्र किया जाएगा। भले ही ऑब्जेक्ट एक-दूसरे को चक्र बनाने के लिए इंगित कर सकते हैं, अगर वे जड़ से कट गए हैं, तो वे अभी भी कचरा कर रहे हैं।

परिशिष्ट ए में अनुपलब्ध वस्तुओं पर अनुभाग देखें: जावा प्लेटफॉर्म प्रदर्शन में कचरा संग्रह के बारे में सच्चाई : नीतिगत विवरण के लिए रणनीतियाँ और रणनीति


14
क्या आपके पास इसके लिए कोई संदर्भ है? इसका परीक्षण करना कठिन है।
तांगें

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

1
बस उस अंतिम टिप्पणी को स्पष्ट करने के लिए ... अंतिम विधि में एक डिबग प्रिंट स्टेटमेंट डालें जो ऑब्जेक्ट के लिए एक अद्वितीय आईडी प्रिंट करता है। आप उन सभी वस्तुओं को देख पाएंगे जो एक दूसरे को संदर्भित करती हैं।
छिपकली का बिल

4
"... पहचानने में होशियार ..." भ्रामक लगता है। GC को चक्रों को पहचानना नहीं है - वे सिर्फ पहुंच से बाहर हैं, इसलिए कचरा
अलेक्जेंडर मालाखोव

86
@tangens "क्या आपके पास इसके लिए कोई संदर्भ है?" कचरा संग्रहण के बारे में एक चर्चा में। श्रेष्ठ। पुन। कभी।
माइकल कोस्मुलस्की

139

हाँ जावा कचरा कलेक्टर परिपत्र-संदर्भ संभालता है!

How?

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

एक साधारण जावा एप्लिकेशन में निम्नलिखित GC जड़ें हैं:

  1. मुख्य विधि में स्थानीय चर
  2. मुख्य सूत्र
  3. मुख्य वर्ग के स्थैतिक चर

यहां छवि विवरण दर्ज करें

यह निर्धारित करने के लिए कि कौन सी वस्तुएं अब उपयोग में नहीं हैं, JVM रुक-रुक कर चलता है, जिसे बहुत उपयुक्त रूप से मार्क-एंड-स्वीप एल्गोरिथ्म कहा जाता है । यह निम्नानुसार काम करता है

  1. एल्गोरिथ्म सभी ऑब्जेक्ट संदर्भों को ट्रेस करता है, जो जीसी जड़ों के साथ शुरू होता है, और हर वस्तु को जीवित पाया जाता है।
  2. चिह्नित वस्तुओं द्वारा कब्जा नहीं किया जाता है कि ढेर स्मृति के सभी पुनः प्राप्त है। यह बस के रूप में चिह्नित है मुक्त, अनिवार्य रूप से अप्रयुक्त वस्तुओं से मुक्त बह।

इसलिए यदि कोई भी वस्तु जीसी जड़ों (भले ही यह स्व-संदर्भित या चक्रीय-संदर्भित हो) से उपलब्ध नहीं है, तो इसे कचरा संग्रहण के अधीन किया जाएगा।

अगर कभी-कभी प्रोग्रामर किसी ऑब्जेक्ट को डिरेल करना भूल जाता है, तो संभवतः यह मेमोरी लीक हो सकती है।

यहां छवि विवरण दर्ज करें

स्रोत: जावा मेमोरी मैनेजमेंट


3
एकदम सही व्याख्या! धन्यवाद! :)
जोवन पेरोविक

उस पुस्तक को जोड़ने के लिए धन्यवाद। यह इस और अन्य जावा विकास विषयों के बारे में महान जानकारी से भरा है!
द्रोज

14
अंतिम चित्र में, एक गैर-पहुंच योग्य वस्तु है, लेकिन यह पहुंच योग्य वस्तुओं के खंड में है।
ला व्लोज़ मेरिल

13

एक कचरा कलेक्टर कुछ "रूट" स्थानों से शुरू होता है जिन्हें हमेशा "पहुंच योग्य" माना जाता है, जैसे कि सीपीयू रजिस्टर, स्टैक और वैश्विक चर। यह उन क्षेत्रों में किसी भी संकेत को खोजने के द्वारा काम करता है, और पुनरावर्ती रूप से वह सब कुछ ढूंढता है जो वे इंगित करते हैं। एक बार यह सब कुछ मिल गया, बाकी सब कचरा है।

बेशक, गति के लिए ज्यादातर काफी भिन्नताएं हैं। उदाहरण के लिए, अधिकांश आधुनिक कचरा संग्राहक "जनरेशनल" होते हैं, जिसका अर्थ है कि वे वस्तुओं को पीढ़ियों में विभाजित करते हैं, और जैसा कि एक वस्तु पुरानी हो जाती है, कचरा कलेक्टर कई बार और लंबे समय के बीच चला जाता है कि यह पता लगाने की कोशिश करता है कि वह वस्तु अभी भी वैध है या नहीं। - यह सिर्फ यह मानने लगता है कि अगर यह लंबे समय तक रहता है, तो संभावना बहुत अच्छी है कि यह लंबे समय तक जीवित रहेगा।

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

एक तरफ दिलचस्प: अक्सर लोग एक कचरा कलेक्टर के इस हिस्से के बीच समानता की डिग्री से आश्चर्यचकित होते हैं और दूरस्थ प्रक्रिया कॉल जैसी चीजों के लिए वस्तुओं को मार्श करने के लिए कोड। प्रत्येक मामले में, आप ऑब्जेक्ट्स के कुछ मूल सेट से शुरू कर रहे हैं, और पॉइंटर्स का पीछा करते हुए उन सभी अन्य वस्तुओं को खोजने के लिए जिन्हें वे संदर्भित करते हैं ...


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

@ Jörg W Mittag: निश्चित रूप से सच है - हालांकि, मुझे एक (उचित रूप से वर्तमान) JVM का पता नहीं है जो संदर्भ गिनती का उपयोग करता है, इसलिए यह संभावना कम से कम (मुझे कम से कम) लगती है कि इससे मूल प्रश्न पर बहुत फर्क पड़ता है।
जेरी कॉफिन

@ Jörg W Mittag: कम से कम मैं डिफ़ॉल्ट रूप से मानता हूं कि जेकेवी आरवीएम वर्तमान में इमिक्स कलेक्टर का उपयोग करता है, जो एक क्षेत्र-आधारित अनुरेखण कलेक्टर है (हालांकि यह संदर्भ गिनती का उपयोग भी करता है)। मुझे यकीन नहीं है कि आप उस संदर्भ गणना का उल्लेख कर रहे हैं, या कोई अन्य कलेक्टर जो बिना ट्रेस किए संदर्भ संदर्भ का उपयोग करता है (मैं बाद का अनुमान लगाऊंगा, क्योंकि मैंने कभी भी इमिक्स को "रिसाइकलर" कहते हुए नहीं सुना है)।
जेरी कॉफिन

मैं थोड़ा मिश्रित गया: रेमंड (?) था Jalapeno में कार्यान्वित किया जाता, एल्गोरिथ्म के बारे में मैं सोच रहा था, जो (था?) Jikes में कार्यान्वित किया जाता है गुप्त संदर्भ गिनती । एटलफ, बेशक, यह कहते हुए कि जेक्स इसका उपयोग करता है या कचरा कलेक्टर काफी व्यर्थ है, यह देखते हुए कि जेक्स और विशेष रूप से एमएमटीके को विशेष रूप से एक ही जेवीएम के भीतर विभिन्न कचरा कलेक्टरों को तेजी से विकसित करने और परीक्षण करने के लिए डिज़ाइन किया गया है।
जोर्ग डब्ल्यू मित्तग

2
उल्टी रेफरेंस काउंटिंग को 2003 में उन्हीं लोगों द्वारा डिजाइन किया गया था जिन्होंने 2007 में Immix को डिजाइन किया था, इसलिए मुझे लगता है कि बाद वाले ने शायद पूर्व को सुपरसीड किया था। यूआरसी को विशेष रूप से डिजाइन किया गया था ताकि इसे अन्य रणनीतियों के साथ जोड़ा जा सके, और वास्तव में यूआरसी पेपर में स्पष्ट रूप से उल्लेख किया गया है कि यूआरसी केवल एक कलेक्टर की ओर एक कदम पत्थर है जो ट्रेसिंग और संदर्भ गिनती के फायदे को जोड़ती है। मुझे लगता है कि Immix वह कलेक्टर है। वैसे भी, रिसाइकलर एक शुद्ध संदर्भ गणना कलेक्टर है, जो फिर भी साइकिल का पता लगा सकता है और इकट्ठा कर सकता है: WWW.Research.IBM.Com/people/d/dfb/recycler.html
Jörg W Mittag

13

तुम सही हो। आपके द्वारा वर्णित कचरा संग्रह का विशिष्ट रूप " संदर्भ गणना " कहलाता है । जिस तरह से यह काम करता है (सबसे सरल मामले में, संदर्भ की गिनती के अधिकांश आधुनिक कार्यान्वयन वास्तव में काफी अलग तरीके से लागू होते हैं), इस तरह दिखता है:

  • जब भी किसी ऑब्जेक्ट का संदर्भ जोड़ा जाता है (जैसे कि यह एक चर या एक क्षेत्र को सौंपा जाता है, विधि को पारित किया जाता है, और इसी तरह), इसकी संदर्भ संख्या 1 से बढ़ जाती है
  • जब भी किसी ऑब्जेक्ट का संदर्भ हटा दिया जाता है (विधि वापस आती है, तो चर दायरे से बाहर हो जाता है, फ़ील्ड को फिर से किसी भिन्न ऑब्जेक्ट को सौंपा जाता है या जिस ऑब्जेक्ट में फ़ील्ड स्वयं कचरा एकत्र हो जाता है), संदर्भ संख्या 1 से कम हो जाती है
  • जैसे ही संदर्भ संख्या 0 से टकराती है, वस्तु का अधिक संदर्भ नहीं होता है, जिसका अर्थ है कि कोई भी इसका उपयोग नहीं कर सकता है, इसलिए यह कचरा है और इसे एकत्र किया जा सकता है

और इस साधारण रणनीति में आपके द्वारा बताई गई समस्या है: यदि A, B और B का संदर्भ A बताता है, तो उनके दोनों संदर्भ मायने कभी 1 से कम नहीं हो सकते हैं , जिसका अर्थ है कि वे कभी एकत्रित नहीं होंगे।

इस समस्या से निपटने के चार तरीके हैं:

  1. अनदेखी करो इसे। यदि आपके पास पर्याप्त मेमोरी है, तो आपके चक्र छोटे और अनूठे हैं और आपका रनटाइम छोटा है, हो सकता है कि आप बस साइकिल एकत्र न करने से दूर हो सकते हैं। शेल स्क्रिप्ट इंटरप्रेटर के बारे में सोचें: शेल स्क्रिप्ट आमतौर पर केवल कुछ सेकंड के लिए चलती हैं और बहुत मेमोरी आवंटित नहीं करती हैं।
  2. अपने संदर्भ की गिनती करने वाले कचरा संग्रहकर्ता को किसी अन्य कचरा संग्राहक के साथ मिलाएं, जिसमें चक्र की समस्या नहीं है। CPython ऐसा करता है, उदाहरण के लिए: CPython में मुख्य कचरा संग्रहकर्ता एक संदर्भ गणना कलेक्टर है, लेकिन समय-समय पर साइकिल को इकट्ठा करने के लिए एक ट्रेसिंग कचरा संग्रहकर्ता चलाया जाता है।
  3. चक्रों का पता लगाएं। दुर्भाग्य से, एक ग्राफ में चक्रों का पता लगाना एक महंगा ऑपरेशन है। विशेष रूप से, इसके लिए बहुत अधिक ओवरहेड की आवश्यकता होती है जो एक ट्रेसिंग कलेक्टर होता है, इसलिए आप बस उन में से एक का उपयोग कर सकते हैं।
  4. एल्गोरिथ्म को उस तरह से लागू न करें जो आप और मैं करेंगे: 1970 के दशक के बाद से, ऐसे कई रोचक एल्गोरिदम विकसित किए गए हैं जो एक ही ऑपरेशन में चक्र का पता लगाने और संदर्भ की गिनती को एक चतुर तरीके से जोड़ते हैं जो कि उन्हें करने की तुलना में काफी सस्ता है। दोनों अलग या एक अनुरेखण कलेक्टर कर रही है।

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

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


1
चूंकि प्रश्न जावा-विशिष्ट है, मुझे लगता है कि यह ध्यान देने योग्य है कि जावा रेफ काउंटिंग का उपयोग नहीं करता है और इसलिए गैर-मौजूद है। इसके अलावा विकिपीडिया के लिए लिंक "आगे पठन" के रूप में उपयोगी होगा। अन्यथा महान अवलोकन!
अलेक्जेंडर मालाखोव

मैंने जेरी कॉफ़िन की पोस्ट पर आपकी टिप्पणियाँ पढ़ी हैं, इसलिए अब मुझे यकीन नहीं हो रहा है :)
अलेक्जेंडर मालाखोव

8

जैसा कि आप वर्णन करते हैं, जावा जीसी वास्तव में व्यवहार नहीं करते हैं। यह कहना अधिक सटीक है कि वे वस्तुओं के एक बेस सेट से शुरू होते हैं, जिसे अक्सर "जीसी रूट" कहा जाता है, और किसी भी वस्तु को इकट्ठा करेंगे जो एक जड़ से नहीं पहुंच सकते हैं।
जीसी जड़ों में शामिल हैं:

  • स्थिर चर
  • वर्तमान में चल रहे धागे के ढेर में स्थानीय चर (सभी लागू 'यह' संदर्भ सहित)

इसलिए, आपके मामले में, एक बार स्थानीय चर a, b, और c आपकी विधि के अंत में दायरे से बाहर चले जाते हैं, तो ऐसी कोई और GC जड़ें नहीं होती हैं, जिनमें प्रत्यक्ष या अप्रत्यक्ष रूप से आपके तीन नोड्स में से कोई एक संदर्भ हो, और वे कचरा संग्रहण के लिए पात्र होंगे।

यदि आप चाहते हैं तो टोफूबीर के लिंक में अधिक विवरण है।


"... वर्तमान में चल रहे धागे के ढेर में ..." क्या यह अन्य धागे के डेटा को दूषित नहीं करने के लिए सभी थ्रेड्स के ढेर को स्कैन कर रहा है?
अलेक्जेंडर मालाखोव

6

यह लेख (अब उपलब्ध नहीं) कचरा कलेक्टर के बारे में गहराई से जाता है (वैचारिक रूप से ... कई कार्यान्वयन हैं)। आपकी पोस्ट का प्रासंगिक हिस्सा "A.3.4 अगम्य" है:

जब कोई और अधिक मजबूत संदर्भ मौजूद नहीं होता है, तो A.3.4 पहुंच से बाहर हो जाता है। जब कोई वस्तु उपलब्ध नहीं होती है, तो यह संग्रह का उम्मीदवार होता है। शब्दांकन पर ध्यान दें: सिर्फ इसलिए कि एक वस्तु संग्रह के लिए एक उम्मीदवार है इसका मतलब यह नहीं है कि इसे तुरंत एकत्र किया जाएगा। JVM संग्रह में देरी करने के लिए स्वतंत्र है जब तक कि वस्तु द्वारा खपत की जाने वाली मेमोरी की तत्काल आवश्यकता नहीं है।



1
लिंक अब उपलब्ध नहीं है
टाइटन्स

1

कचरा संग्रह का आमतौर पर मतलब नहीं है "कुछ वस्तु को साफ करें यदि और कुछ नहीं तो उस वस्तु की ओर इशारा कर रहा है" (यह संदर्भ गिनती है)। कचरा संग्रह मोटे तौर पर उन वस्तुओं को खोजने का मतलब है जो कार्यक्रम से नहीं पहुंच सकते हैं।

इसलिए आपके उदाहरण में, a, b और c के दायरे से बाहर जाने के बाद, उन्हें GC द्वारा एकत्र किया जा सकता है, क्योंकि आप इन वस्तुओं को अब एक्सेस नहीं कर सकते हैं।


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

1
कचरा संग्रहण के लिए संदर्भ गणना दो मुख्य कार्यान्वयन रणनीतियों में से एक है। (अन्य ट्रेसिंग है।)
जार्ग डब्ल्यू मित्तग

3
@ Jörg: आज ज्यादातर समय, जब लोग कचरा इकट्ठा करने वालों के बारे में बात करते हैं, तो वे किसी तरह के mark'n'sweep एल्गोरिथ्म के आधार पर कलेक्टरों का जिक्र करते हैं। रेफ काउंटिंग आमतौर पर वही होता है जो आपके पास होता है अगर आपके पास कचरा उठाने वाला नहीं है। यह सच है कि रेफ काउंटिंग एक कचरा संग्रहण रणनीति है, लेकिन आज शायद ही कोई ऐसा जीसी विद्यमान है जो इसके शीर्ष पर बना हो, इसलिए यह कहना कि यह एक जीसी रणनीति है, बस लोगों को भ्रमित करने वाली है क्योंकि व्यवहार में यह अब जीसी नहीं है। रणनीति लेकिन स्मृति को प्रबंधित करने का एक वैकल्पिक तरीका।
फ्रेड्रिक

1

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

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