कचरा संग्रहण में हैश टेबल का उपयोग करने से मार्क और स्वीप की दुनिया की समस्या का समाधान होगा?


13

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

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

क्या मेरे विचार में कोई गलती है?

जवाबों:


19

संदर्भ को अद्यतन करना केवल एक चीज नहीं है जिसके लिए एक ठहराव की आवश्यकता होती है। मानक एल्गोरिदम को आमतौर पर "मार्क-स्वीप" के तहत समूहीकृत किया जाता है, सभी यह मानते हैं कि यह चिह्नित किए जाने के दौरान पूरी वस्तु ग्राफ अनलक्ड रह गई है। सही ढंग से संशोधनों (नई वस्तुओं का निर्माण, संदर्भ बदल गए) को त्रि-रंग एल्गोरिदम की तरह मुश्किल वैकल्पिक एल्गोरिदम की आवश्यकता होती है। छाता शब्द "समवर्ती कचरा संग्रह" है।

लेकिन हाँ, संघनन के बाद के संदर्भों को अद्यतन करने के लिए भी विराम की आवश्यकता होती है। और हाँ, अप्रत्यक्ष (उदाहरण के लिए एक सतत वस्तु आईडी और वास्तविक संकेत करने के लिए एक हैश तालिका के माध्यम से) बहुत रोक को कम कर सकते हैं। यह भी संभव हो सकता है कि यदि कोई ऐसा चाहता है तो वह इस हिस्से को लॉक-फ्री बना सकता है। यह अभी भी किसी भी निम्न-स्तरीय साझा-मेमोरी संगामिति के रूप में सही पाने के लिए मुश्किल है, लेकिन यह काम नहीं करेगा कोई मौलिक कारण है।

हालांकि , इसके गंभीर नुकसान होंगे। अतिरिक्त जगह लेने के अलावा ( सभी वस्तुओं के लिए कम से कम दो अतिरिक्त शब्द), यह हर डेरेफेरेंस को बहुत अधिक महंगा बनाता है। यहां तक ​​कि एक विशेषता के रूप में सरल कुछ भी अब एक पूर्ण हैश तालिका खोज शामिल है। मुझे लगता है कि प्रदर्शन में वृद्धि वृद्धिशील अनुरेखण की तुलना में अधिक खराब होगी।


वैसे आज हमारे पास बहुत सी मेमोरी है इसलिए हम 50 एमबी टेबल और हैश को साधारण
मोडुलो

3
@mrpyo हैश तालिका के आकार को लाने, modulo ऑपरेशन, वास्तविक वस्तु सूचक प्राप्त करने के लिए हैश तालिका ऑफसेट से dereference, वस्तु के लिए ही dereference। इसके अलावा संभवतः कुछ रजिस्टर फेरबदल। हम 4+ निर्देशों पर समाप्त होते हैं। इसके अलावा, इस योजना में मेमोरी लोकलिटी से संबंधित समस्याएं हैं: अब, हैश टेबल और डेटा दोनों को ही कैश में फिट होना है।
अमोन

@mrpyo आपको प्रति वस्तु, सही में एक प्रविष्टि (ऑब्जेक्ट आईडी -> वर्तमान पता) की आवश्यकता है? और कैसे सस्ते हैश समारोह है की परवाह किए बिना, आप होगा टकराव और उन्हें हल करने की जरूरत है। साथ ही आमोन ने क्या कहा।

सीपीएम के 50MB या उससे अधिक कैश होने से पहले @amon यह केवल समय की बात है :)
Móż

1
@ @ जब तक हम एक चिप पर 50 MiB ट्रांजिस्टर लगा सकते हैं और तब भी इसमें विलंबता कम होती है, तो यह L1 या L2 कैश के रूप में काम करता है (L3 कैश पहले से ही आकार में 15 MiB तक है, लेकिन आमतौर पर AFAIK और दूर से चिप एल 1 और एल 2 की तुलना में बदतर विलंबता, हमारे पास मुख्य रूप से मुख्य मेमोरी (और इसमें डालने के लिए डेटा) की बड़ी मात्रा होगी। तालिका को निश्चित आकार नहीं दिया जा सकता है, इसे ढेर के साथ बढ़ना चाहिए।

19

कंप्यूटर विज्ञान में सभी समस्याओं को अप्रत्यक्ष के एक और स्तर द्वारा हल किया जा सकता है… अप्रत्यक्ष की बहुत अधिक परतों की समस्या को छोड़कर

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

मैंने कहा कि आपका प्रस्ताव केवल समस्या को हल करता है, इसे हल नहीं करता है। मुद्दा ऑब्जेक्ट आईडी के पुन: उपयोग के आसपास है। ऑब्जेक्ट आईडी अब हमारे पॉइंटर्स के समतुल्य हैं, और केवल पते की एक सीमित मात्रा है। यह बोधगम्य है (एक 32 बिट सिस्टम पर esp) कि आपके कार्यक्रम के जीवनकाल के दौरान, INT_MAX से अधिक वस्तुओं का निर्माण किया गया होगा, जैसे एक पाश में

while (true) {
    Object garbage = new Object();
}

यदि हम प्रत्येक ऑब्जेक्ट के लिए ऑब्जेक्ट आईडी बढ़ाते हैं, तो हम किसी बिंदु पर आईडी से बाहर निकल जाएंगे। इसलिए हमें यह पता लगाना होगा कि कौन सी आईडी अभी भी उपयोग में हैं और जो मुफ्त हैं ताकि उन्हें पुनः प्राप्त किया जा सके। जाना पहचाना? अब हम वापस वर्ग एक पर हैं।


एक अनुमान के अनुसार ID का उपयोग कर सकते हैं जो केवल 'काफी पर्याप्त' कह रहे हैं 256 बिट bignums? मैं यह नहीं कह रहा हूं कि यह विचार कुल मिलाकर अच्छा है, लेकिन आप आईडीएस का पुन: उपयोग कर सकते हैं।
वैधता

@Vality वास्तविक रूप से हां - जहां तक ​​हम देख सकते हैं कि आईडी के पुन: उपयोग के मुद्दे के आसपास मिलेगा। लेकिन यह सिर्फ एक और "640K किसी के लिए पर्याप्त होना चाहिए" तर्क है, और वास्तव में समस्या को हल नहीं करता है। एक और भयावह पहलू यह है कि सभी वस्तुओं (और हैश टेबल) का आकार इन ओवरसाइज़्ड छद्म बिंदुओं को समायोजित करने के लिए बढ़ाना होगा, और हैश एक्सेस के दौरान हमें इस बिगिन की तुलना अन्य आईडी से करने की आवश्यकता होगी जो संभवतः कई रजिस्टरों को हॉग करेंगे। , और पूरा करने के लिए कई निर्देश लें (64 बिट पर: 8 × लोड, 4 × तुलना, 3 × और जो कि मूल ints पर 5 × वृद्धि है)।
आमोन

हाँ, आप कुछ समय बाद आईडी से बाहर निकल जाएंगे और उन्हें उन सभी को बदलने की आवश्यकता होगी, जिन्हें एक ठहराव की आवश्यकता होगी। लेकिन संभवतः यह एक दुर्लभ घटना होगी ...
mrpyo

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

@amon: दुनिया में इससे कहीं अधिक कोड है कि एक बार 64 बिट आईडी (584 साल के नैनोसेकंड) को लपेटने के बाद आप गलत हो जाएंगे, और आप शायद मेमोरी आवंटन के लिए व्यवस्था कर सकते हैं ताकि आप 1 काउंटर ले सकें, खासकर जब आप वैश्विक काउंटर पर शार्प न करें आईडी बाहर थूकता है!)। लेकिन यकीन है, अगर आप उस पर भरोसा करने की जरूरत नहीं है तो आप नहीं करते हैं।
स्टीव जेसोप

12

आपके विचार की पंक्ति में कोई त्रुटि नहीं है, आपने मूल जावा कचरा संग्रहकर्ता के काम करने के तरीके के बहुत करीब से वर्णन किया है

मूल जावा वर्चुअल मशीन [6] और कुछ स्मॉलटॉक वर्चुअल मशीन ऑब्जेक्ट्स को संदर्भित करने के लिए अप्रत्यक्ष संकेत का उपयोग करती है, जिसे [6] में हैंडल कहा जाता है। हैंडल कचरा संग्रहण के दौरान वस्तुओं को आसानी से स्थानांतरित करने की अनुमति देता है, हैंडल के साथ, प्रत्येक वस्तु के लिए एक सीधा सूचक होता है: इसके हैंडल में एक। ऑब्जेक्ट के सभी अन्य संदर्भ अप्रत्यक्ष रूप से हैंग-डीएलई के माध्यम से होते हैं। इस तरह के हैंडल-आधारित मेमोरी सिस्टम में, जबकि ऑब्जेक्ट एड्रेस, वस्तुओं के जीवनकाल में बदल जाते हैं और इसलिए इसका उपयोग हैशिंग के लिए नहीं किया जा सकता है, हैंडल एड्रेस स्थिर रहते हैं।

कचरा-एकत्रित वस्तुओं का स्थान और समय-कुशलता पर अंकुश

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

जावा वर्चुअल मशीन विशिष्टता (1997)

तो यह काम करता है, यह करने की कोशिश की गई है, और इसकी अक्षमता से जनरेशनल मार्क और स्वीप सिस्टम का विकास हुआ।


संभवत: ये हैंडल हैशटेबल (प्रश्न में) की तरह नहीं थे, हालांकि? कोई जरूरत नहीं है, बस एक संरचना जिसमें एक पॉइंटर है। फिर हैंडल सभी समान आकार के होते हैं ताकि उन्हें ढेर आवंटन से बाहर आवंटित किया जा सके। इसकी प्रकृति से जिसे आंतरिक संघनन की आवश्यकता नहीं है क्योंकि यह खंडित नहीं होता है। आप उस आवंटनकर्ता द्वारा उपयोग किए गए बड़े ब्लॉकों की अक्षमता पर शोक कर सकते हैं, स्वयं को स्थानांतरित करने के लिए। जिसे अप्रत्यक्ष रूप से किसी अन्य स्तर से हल किया जा सकता है ;-)
स्टीव जेसप

@SteveJessop हाँ, जीसी कार्यान्वयन में एक हैशटेबल नहीं था, हालांकि हैंडल का मूल्य भी मूल्य द्वारा वापस आ गया थाObject.getHashCode()
पीट किर्कम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.