2011-06-13 12 views
6

क्या कोई मेमोरी लीक को रोकने के लिए उपयोग किए जाने वाले असाइनमेंट-टू-नल फिक्स की प्रकृति के संबंध में मेरे लिए खुजली खरोंच कर सकता है?जावास्क्रिप्ट मेमोरी लीक: ऑब्जेक्ट को शून्य काम क्यों सौंपेगा?

हम सब निम्नलिखित तकनीक, डोम वस्तु और जे एस वस्तु के बीच वृत्तीय संदर्भ को रोकने के लिए आदेश में मेमोरी लीक को रोकने के लिए के साथ परिचित हैं:

function foo() { 
     var ele = document.getElementById("someParagraphId"); 

     ele.onclick = function() { 
     //some action here 
     }; 

     ele = null; 
    } 

सवाल क्यों करेंगे ऊपर काम है? "Ele" को शून्य पर सेट करना निश्चित रूप से परिपत्र संदर्भों को रोक देगा, लेकिन क्या यह "ele" के भविष्य के संदर्भों को भी रोक नहीं पाएगा?

function foo() { 
     var ele = document.getElementById("someParagraphId"); 

      ele.onclick = function() { 
       console.log("accessing ele ... after set to null " + ele.onclick); 
      }; 

     ele = null; 

    } 

और फिर भी ईवेंट श्रोता आग लगती है। यह शिकायत करेगा कि "ele" ऑब्जेक्ट शून्य है (जो हम उम्मीद करेंगे)।

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

eventHandlerRef = //assignment to "ele.onclick" handler/listener; 

यदि उपरोक्त जैसा कोई संदर्भ होना था, तो असाइनमेंट-टू-नल फिक्स कार्यान्वयन पर निर्भर नहीं होगा? या, यह ईसीएमएस्क्रिप्ट विनिर्देश का हिस्सा है।

मेरी समझ से, यह तय हमेशा ब्राउज़र ब्राउज़र सुरक्षित रहा है। मैं कई उदाहरणों में नहीं आया हूं जो शून्य असाइनमेंट लागू करने से पहले ब्राउज़र प्रकार का पता लगाने/स्नीफ करने पर विशिष्ट उल्लेख करता है।

=============== संपादित ==================

मैं की वजह से लगता है जिस तरह से मैंने सवाल उठाया है, वह अनजाने में सीधे चर्चा कर सकता है जो मैं व्यक्त करने की कोशिश कर रहा था। अवधारणाओं के एक जोड़े कि उनका संदर्भ दिया जा:

वस्तु आला/वस्तु संदर्भ संभालता है:

var obj1, obj2; 
    obj1 = {foo: "bar"}; //obj1 points to the an area of the heap allocated 
          //for the object literal. 

obj2 = obj1;  //obj2 points to the same position in the heap 
         //as obj1. 

//obj1 = null or 
obj1 = {/*another obj literal*/} //the new object literal is created 
             //and allocated in some other part 
             //in the heap, and obj1 now points 
             //to the new location. 

//obj2 is unaffected by obj1's re-assignment. 
ऊपर

जहाँ मेरे खुजली झूठ नहीं है, और मैं पंक्ति जोड़कर अफसोस:

console.log("accessing ele ... after set to null " + ele.onclick); 

उपर्युक्त यह एक बंद प्रश्न बनाता है। मुझे उम्मीद है कि मूल पोस्ट में संकेत के रूप में त्रुटि को फेंक दिया जाएगा।

मेरा खुजली संदर्भ के साथ अधिक है ... किसी कारण से, मेरे दिमाग में, मैं सोचता रहता हूं कि जावास्क्रिप्ट इंजन सीधे ele.onlick() को कॉल करेगा जब ईवेंट आग को शून्य पर रखता है और सेट करता है, निम्न प्रवाह के समान है :

var obj = {}; 
obj.method = function() {}; 

var objRef = obj; 

obj = null; 

//The Javascript Engine calling objRef.method when event triggered. 

मेरे खुजली आता है:

var obj = {}; 
obj.method = function() {}; 

obj = null; 
//error calling obj.method(), i.e., obj is null 

यह देखते हुए कि हम मूल पोस्ट कि ईवेंट हैंडलर अभी भी हाथी अशक्त करने के लिए स्थापित किया गया है के बाद आग में पता है, मेरे मन में प्रवाह के अधिक समान है सवाल के नीचे, ऊपर है कि कैसे अधिकांश जा vascript कार्यान्वयन कार्य, जहां कुछ आंतरिक संदर्भ इवेंट हैंडलर को इंगित कर रहा है, और यह आंतरिक संदर्भ कहा जाता है जब ईवेंट ट्रिगर होता है?

या, अलग ढंग से phrased क्या बुला एकele.onclick() सीधे (पल डिजाइन और वास्तुकला के मुद्दों के लिए दरकिनार) से एक जावास्क्रिप्ट इंजन कार्यान्वयन रोक रहा है?

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

+0

मैंने आपके संपादन को संबोधित करने के लिए अपना उत्तर संपादित कर दिया है। – zneak

उत्तर

0

चूंकि आपको ele को document.getElementById("someParagraphId") पर कॉल करके पहली जगह मिलती है, तो ele असाइन करने से पहले ऑब्जेक्ट का संदर्भ पहले से ही स्मृति में मौजूद है। यह दस्तावेज़ का एक हिस्सा है - बेशक ele के अलावा स्मृति में इसका संदर्भ है।

6

सभी पुराने जवाब ट्रैश हो, और संपादित :)

को संबोधित कर के एक आसान उदाहरण लेते हैं: textContent

var ele = document.getElementById('foo'); 
ele.textContent = 'abc'; 
ele = null; 

इस कोड को सेट करने के लिए abc#foo की textContent, और ele के संदर्भ में छोड़ देता है। अब क्या होता है अगर मैं #foo फिर? के लिए पूछना ...

var ele = document.getElementById('foo'); 
ele.textContent = 'abc'; 
ele = null; 
ele = document.getElementById('foo'); 
console.log('#foo is ' + ele.textContent); 

यह "#foo is abc" प्रवेश करेंगे। यह बस इंगित करता है कि #foo मेरी स्क्रिप्ट के बाहर, और document इसका संदर्भ रखता है (क्योंकि मुझे इसे document पर एक विधि बुलाया गया था)। यह ईवेंट हैंडलर के साथ भी काम करता है।

var ele = document.getElementById('foo'); 
ele.onclick = function() { console.log('abc'); }; 
ele = null; 
ele = document.getElementById('foo'); 
console.log('#foo.onclick is ' + ele.onclick); 

ईवेंट हैंडलर एक विशेष प्रकार की संपत्ति नहीं हैं। वे केवल वे चर हैं जिन पर आप संदर्भ लिखते हैं (कार्यों के लिए)। ये मोटे तौर पर कार्यात्मक भाषा विशेषताएं हैं, जहां कार्यों को सरल मानों के रूप में उपयोग किया जा सकता है। जावास्क्रिप्ट कार्यान्वयन ele संदर्भ के बजाय, ईवेंट हैंडलर को DOM संदर्भ से कॉल करता है। आइए document.getElementById के बिना, एक और सरल उदाहरण बनाएं।

var a = {}; 
var b = a; 
b.foo = function() { console.log("hello world!"); }; 
console.log(a.foo + " is the same as " + b.foo); 
b = null; 
console.log("Even though b is " + b + ", a.foo is still " + a.foo); 
a.foo(); 

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

इस तरह, आप वस्तुओं के सही व्यवहार को प्रभावित किए बिना परिपत्र निर्भरताओं को तोड़ने के संदर्भों को निरस्त कर सकते हैं।

+0

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

0

मैं एक जावास्क्रिप्ट गुरु से बहुत दूर हूं; लेकिन मुझे लगता है कि मैं परिवर्तनीय और ऑब्जेक्ट के बीच अंतर का अनुस्मारक प्रदान करके कम से कम आंशिक रूप से आपके प्रश्न का उत्तर दे सकता हूं। आइए एक समय में अपने कोड को एक पंक्ति से आगे बढ़ें।

var ele = document.getElementById("someParagraphId"); 

यहाँ हम दो बातें कर रहे हैं: उस चर को

  • एक चर (ele)
  • की घोषणा एक डोम तत्व के लिए संदर्भ नियत (एक वस्तु)

अगला:

ele.onclick = function() { 
    console.log("accessing ele ... after set to null " + ele.onclick); 
}; 

यहाँ हम प्रयोग कर रहे हैं चरeleवस्तु (फिर से, एक डोम तत्व) है जो इसे का संदर्भ के onclick घटना के लिए एक कॉलबैक आवंटित करने के लिए।

अंत:

ele = null; 

अंत में हम अपने ele चर करने के लिए एक null संदर्भ आवंटित। यह अब कुछ समय पहले किए गए ऑब्जेक्ट का संदर्भ नहीं देता है। हालांकि, वह ऑब्जेक्ट अभी भी वहां है, उसी onclick हैंडलर के साथ; यह नहीं बदला है।

तथ्य यह है कि हैंडलर अभी भी बुलाया गया है सही व्यवहार है। अब, त्रुटि के लिए के रूप में, चलो कि डोम तत्व के onclick ईवेंट हेतु निर्दिष्ट समारोह पर फिर से विचार करते हैं:

console.log("accessing ele ... after set to null " + ele.onclick); 

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

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