जावास्क्रिप्ट कचरा संग्रह क्या है?


297

जावास्क्रिप्ट कचरा संग्रह क्या है? बेहतर कोड लिखने के लिए एक वेब प्रोग्रामर के लिए जावास्क्रिप्ट कचरा संग्रहण के बारे में समझना क्या महत्वपूर्ण है?



जवाबों:


192

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

उस पृष्ठ से उद्धृत:

JScript एक नोजेनरेशनल मार्क-एंड-स्वीप कचरा कलेक्टर का उपयोग करता है। यह इस तरह काम करता है:

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

  • हर अब और फिर कचरा कलेक्टर चलाता है। पहले यह हर वस्तु, चर, स्ट्रिंग, आदि पर एक "चिह्न" डालता है - जीसी द्वारा ट्रैक की गई सभी मेमोरी। (JScript आंतरिक डेटा संरचना का आंतरिक रूप से उपयोग करता है और उस संरचना में बहुत सारे अतिरिक्त अप्रयुक्त बिट्स हैं, इसलिए हम उनमें से एक सेट करते हैं।)

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

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

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

ऐतिहासिक नोट: उत्तर के पहले संशोधन में deleteऑपरेटर के लिए एक गलत संदर्भ था । जावास्क्रिप्ट में deleteऑपरेटर एक ऑब्जेक्ट से एक संपत्ति निकालता है , और deleteसी / सी ++ में पूरी तरह से अलग है ।


27
Apple गाइड त्रुटिपूर्ण है: ऑटोर deleteगलत तरीके से उपयोग करता है; उदाहरण के लिए, इसके बजाय delete foo, आपको पहले इवेंट श्रोता को इसके माध्यम से निकालना चाहिए window.removeEventListener()और फिर foo = nullचर को अधिलेखित करने के लिए उपयोग करना चाहिए ; IE में, delete window.foo(लेकिन नहीं delete foo) भी काम किया होता अगर fooवैश्विक होता, लेकिन फिर भी यह FF या ओपेरा में नहीं होता
क्रिस्चो

3
विदित हो कि एरिक के लेख को "केवल ऐतिहासिक उद्देश्यों के लिए" माना जाना चाहिए। लेकिन यह अभी भी जानकारीपूर्ण है।
पीटर इवान

2
यह भी ध्यान दें - IE 6 और 7 एक गैर-विशिष्ट चिह्न और झाडू कचरा संग्रहकर्ता का उपयोग न करें। वे एक साधारण संदर्भ गिनती कचरा कलेक्टर का उपयोग करते हैं, जो कचरा संग्रह के साथ परिपत्र संदर्भ समस्याओं के लिए अधिक असुरक्षित है।
डग

1
ECMAScript deleteएक अपरेटिव ऑपरेटर (एक अभिव्यक्ति) है, न कि एक स्टेटमेंट (यानी:) delete 0, delete 0, delete 3। अभिव्यक्ति कथन द्वारा व्यक्त किए जाने पर यह कथन जैसा लगता है।
हाइड्रोपर

उस समय का उत्तर अब पुराना हो चुका है, 2012 तक, आधुनिक ब्राउज़र एक मार्क / स्वीप एल्गरथेम का उपयोग करते हैं .. इसलिए यह अब निर्भर नहीं है। संदर्भ: developer.mozilla.org/en-US/docs/Web/JavaScript/…
sksallaj

52

DOM ऑब्जेक्ट्स शामिल होने पर परिपत्र संदर्भों से सावधान रहें:

जावास्क्रिप्ट में मेमोरी लीक पैटर्न

ध्यान रखें कि स्मृति को केवल तभी पुनः प्राप्त किया जा सकता है जब ऑब्जेक्ट में कोई सक्रिय संदर्भ न हों। यह क्लोजर और इवेंट हैंडलर के साथ एक आम नुकसान है, क्योंकि कुछ जेएस इंजन यह जांच नहीं करेंगे कि कौन से चर वास्तव में आंतरिक कार्यों में संदर्भित हैं और बस एन्कोडिंग कार्यों के सभी स्थानीय चर रखें।

यहाँ एक सरल उदाहरण दिया गया है:

function init() {
    var bigString = new Array(1000).join('xxx');
    var foo = document.getElementById('foo');
    foo.onclick = function() {
        // this might create a closure over `bigString`,
        // even if `bigString` isn't referenced anywhere!
    };
}

bigStringजब तक घटना हैंडलर के आसपास न हो, एक भोले जेएस कार्यान्वयन लागू नहीं हो सकता । इस समस्या को हल करने के कई तरीके हैं, उदाहरण bigString = nullके लिए init()( deleteस्थानीय चर और फ़ंक्शन तर्क के लिए काम नहीं करेगा) सेटिंग : deleteऑब्जेक्ट से गुण हटाता है, और चर ऑब्जेक्ट दुर्गम है - सख्त मोड में ES5 भी ReferenceErrorअगर आप कोशिश करेंगे तो फेंक देंगे एक स्थानीय चर को नष्ट करने के लिए!)।

यदि आप स्मृति खपत के लिए परवाह करते हैं तो मैं अनावश्यक बंद से बचने की सलाह देता हूं।


20
डोम सर्कुलर संदर्भ बग JScript के लिए विशिष्ट है - कोई अन्य ब्राउज़र इसे ग्रस्त नहीं करता है लेकिन IE। वास्तव में मुझे पूरी तरह से यकीन है कि ECMAScript युक्ति स्पष्ट रूप से बताती है कि GC को ऐसे चक्रों को संभालने में सक्षम होना चाहिए: - /
olliej

@olliej: मुझे ECMAScript युक्ति में GC का कोई उल्लेख नहीं दिखता है ।
Janus Troelsen


16

ब्लॉग से लिया गया अच्छा उद्धरण

DOM घटक "कचरा एकत्र" है, जैसा कि JScript घटक है, जिसका अर्थ है कि यदि आप या तो घटक के भीतर एक ऑब्जेक्ट बनाते हैं, और फिर उस ऑब्जेक्ट का ट्रैक खो देते हैं, तो यह अंततः साफ हो जाएगा।

उदाहरण के लिए:

function makeABigObject() {
var bigArray = new Array(20000);
}

जब आप उस फ़ंक्शन को कॉल करते हैं, तो JScript घटक एक ऑब्जेक्ट (bigArray नाम) बनाता है जो फ़ंक्शन के भीतर पहुंच योग्य है। जैसे ही फ़ंक्शन वापस आता है, हालांकि, आप bigArray का "ट्रैक खो देते हैं" क्योंकि अब इसे संदर्भित करने का कोई तरीका नहीं है। ठीक है, JScript घटक को पता चलता है कि आपने इसका ट्रैक खो दिया है, और इसलिए BigArray को साफ किया जाता है - इसकी मेमोरी पुनः प्राप्त होती है। DOM कंपोनेंट में एक ही तरह की चीज काम करती है। यदि आप कहते हैं document.createElement('div'), या कुछ समान है, तो DOM घटक आपके लिए एक ऑब्जेक्ट बनाता है। एक बार जब आप किसी तरह उस वस्तु का ट्रैक खो देते हैं, तो DOM घटक संबंधित को साफ कर देगा।


13

मेरे ज्ञान का सबसे अच्छा करने के लिए, जावास्क्रिप्ट की वस्तुओं को समय-समय पर कचरा एकत्र किया जाता है जब ऑब्जेक्ट के लिए कोई संदर्भ शेष नहीं होता है। यह कुछ ऐसा है जो स्वचालित रूप से होता है, लेकिन यदि आप यह देखना चाहते हैं कि यह C ++ स्तर पर कैसे काम करता है, तो यह WebKit या V8 स्रोत कोड पर एक नज़र डालने के लिए समझ में आता है

आमतौर पर आपको इसके बारे में सोचने की ज़रूरत नहीं है, हालांकि, पुराने ब्राउज़रों में, जैसे IE 5.5 और IE 6 के शुरुआती संस्करण, और शायद वर्तमान संस्करण, क्लोज़र परिपत्र संदर्भ बनाएंगे, जब अनियंत्रित मेमोरी को खा जाएगा। उस विशेष मामले में जिसका मतलब है कि मैं क्लोज़र के बारे में हूं, यह तब था जब आपने एक डोम ऑब्जेक्ट में जावास्क्रिप्ट संदर्भ जोड़ा था, और डोम ऑब्जेक्ट पर एक ऑब्जेक्ट जिसे जावास्क्रिप्ट ऑब्जेक्ट पर वापस भेजा गया था। मूल रूप से इसे कभी भी एकत्र नहीं किया जा सकता है, और अंततः ओएस का परीक्षण करने वाले ऐप्स में अस्थिर होने का कारण होगा जो क्रैश बनाने के लिए लूप किए गए थे। व्यवहार में ये लीक आमतौर पर छोटे होते हैं, लेकिन अपने कोड को साफ रखने के लिए आपको जावास्क्रिप्ट ऑब्जेक्ट को DOM ऑब्जेक्ट पर डिलीट करना चाहिए।

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


क्या IE के नए संस्करणों में जावास्क्रिप्ट -> DOM -> जावास्क्रिप्ट परिपत्र संदर्भ समस्या हल हो गई है? यदि हां, तो कब से? मुझे लगा कि यह वास्तुशिल्प रूप से बहुत गहरा है और कभी भी स्थिर होने की संभावना नहीं है। क्या आपके पास कोई स्रोत है?
एरिक्कलेन

बस किस्सा है। मैं IE 8 में पागल लीक नहीं देखा है मानक मोड में चल रहा है, टूटी हुई मोड नहीं। मैं अपनी प्रतिक्रिया समायोजित करूंगा।
हीट मेसर

1
@erikkallen: हाँ, जीसी बग को IE संस्करण 8+ में तय किया गया है, क्योंकि पुराने बहुत ही भोले कचरा संग्रह एल्गोरिथ्म का उपयोग कर रहे थे, जिससे जीसी को एक-दूसरे का जिक्र करने वाली वस्तुओं की एक जोड़ी प्राप्त करना असंभव हो गया था। नए mark-and-sweepस्टाइल के एल्गोरिदम इसका ध्यान रखते हैं
कुमारहर्ष

6

कचरा संग्रह (जीसी) उन वस्तुओं को हटाकर स्वचालित मेमोरी प्रबंधन का एक रूप है जिनकी अब कोई आवश्यकता नहीं है।

मेमोरी के साथ कोई भी प्रक्रिया सौदा इन चरणों का पालन करें:

1 - आप की जरूरत है अपनी स्मृति स्थान आवंटित करें

2 - कुछ प्रसंस्करण करते हैं

3 - इस मेमोरी स्पेस को फ्री करें

वहाँ दो मुख्य एल्गोरिथ्म का पता लगाने के लिए उपयोग किया जाता है जो वस्तुओं की अब कोई आवश्यकता नहीं है।

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

मार्क-एंड-स्वीप एल्गोरिथ्म : प्रत्येक ऑब्जेक्ट को रूट सोर्स से कनेक्ट करें। कोई भी वस्तु जड़ या अन्य वस्तु से नहीं जुड़ती है। यह ऑब्जेक्ट हटा दिया जाएगा।

वर्तमान में अधिकांश आधुनिक ब्राउज़र दूसरे एल्गोरिथ्म का उपयोग कर रहे हैं।


1
और इसका एक स्रोत जोड़ने के लिए, MDN देखें: developer.mozilla.org/en-US/docs/Web/JavaScript/…
Xenos

4

"कंप्यूटर विज्ञान में, कचरा संग्रह (जीसी) स्वचालित मेमोरी प्रबंधन का एक रूप है। कचरा संग्रहकर्ता, या सिर्फ कलेक्टर, कचरे को पुनः प्राप्त करने का प्रयास करता है, या उन वस्तुओं द्वारा उपयोग की जाने वाली मेमोरी जो कभी भी एप्लिकेशन द्वारा एक्सेस या म्यूट नहीं किया जाएगा।"

सभी जावास्क्रिप्ट इंजन के पास अपने स्वयं के कचरा संग्रहकर्ता होते हैं, और वे भिन्न हो सकते हैं। ज्यादातर समय आपको उनसे निपटना नहीं पड़ता क्योंकि वे वही करते हैं जो वे करने वाले थे।

बेहतर कोड लिखना ज्यादातर इस बात पर निर्भर करता है कि आप प्रोग्रामिंग सिद्धांतों, भाषा और विशेष रूप से कार्यान्वयन को कितना अच्छा जानते हैं।


1

जावास्क्रिप्ट कचरा संग्रह क्या है?

जाँच इस

बेहतर कोड लिखने के लिए एक वेब प्रोग्रामर के लिए जावास्क्रिप्ट कचरा संग्रहण के बारे में समझना क्या महत्वपूर्ण है?

जावास्क्रिप्ट में आप मेमोरी आवंटन और डील्लोकेशन के बारे में परवाह नहीं करते हैं। संपूर्ण समस्या को जावास्क्रिप्ट इंटरप्रेटर की मांग की जाती है। जावास्क्रिप्ट में अभी भी लीक संभव है, लेकिन वे दुभाषिया के कीड़े हैं। यदि आप इस विषय में रुचि रखते हैं तो आप www.memorymanagement.org पर अधिक पढ़ सकते हैं


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

3
मेमोरी लीक जावास्क्रिप्ट में एक जानवर हैं। यदि आप एक सरल "कॉलेज प्रोजेक्ट" एप्लिकेशन लिख रहे हैं, तो कोई चिंता नहीं है। लेकिन जब आप उच्च-प्रदर्शन एंटरप्राइज़-स्तरीय एप्लिकेशन लिखना शुरू करते हैं, तो जावास्क्रिप्ट में मेमोरी प्रबंधन एक आवश्यक है।
डग

1

खिड़कियों पर आप Drip.exe का उपयोग कर सकते हैं स्मृति लीक खोजने के लिए या जांचें कि क्या आपके मुफ्त मेम दिनचर्या काम करती है।

यह वास्तव में सरल है, बस एक वेबसाइट URL दर्ज करें और आप एकीकृत IE रेंडरर की मेमोरी खपत देखेंगे। फिर ताज़ा करें, यदि मेमोरी बढ़ती है, तो आपको वेबपेज पर कहीं स्मृति रिसाव मिला। लेकिन यह देखने के लिए भी बहुत उपयोगी है कि क्या IE के लिए मेमोरी काम को मुक्त करने के लिए दिनचर्या।


1

संदर्भ प्रकार ऑब्जेक्ट को सीधे उस चर में संग्रहीत नहीं करता है जिसे इसे सौंपा गया है, इसलिए इस उदाहरण में ऑब्जेक्ट चर वास्तव में ऑब्जेक्ट उदाहरण में नहीं है। इसके बजाय, यह मेमोरी में उस स्थान पर एक पॉइंटर (या संदर्भ) रखता है जहां ऑब्जेक्ट मौजूद है

var object = new Object();

यदि आप एक चर दूसरे को सौंपते हैं, तो प्रत्येक चर सूचक की एक प्रति प्राप्त करता है, और दोनों अभी भी स्मृति में एक ही वस्तु को संदर्भित करते हैं।

var object1 = new Object();
var object2 = object1;

एक वस्तु की ओर इशारा करते हुए दो चर

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

var object1 = new Object();
// do something
object1 = null; // dereference

डेरीफेरिंग ऑब्जेक्ट विशेष रूप से बहुत बड़े अनुप्रयोगों में महत्वपूर्ण है जो लाखों ऑब्जेक्ट का उपयोग करते हैं।

ऑब्जेक्ट ओरिएंटेड जावास्क्रिप्ट के सिद्धांतों से - निकोलस सी। ज़कास

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