2011-08-25 13 views
13

मैं जावास्क्रिप्ट के बहुत सारे के साथ एक बड़े उद्यम अनुप्रयोग पर काम कर रहा हूं। पर्याप्त है कि मैं अपने पिछले 5 वर्षों के विकास के दौरान बनाए गए सभी छोटे परिपत्र संदर्भों को संभवतः पार नहीं कर सकता हूं। समाधान शोध जबकि मैं इस छोटे से jQuery हैक/पैच भर में आया था:jQuery लीक हल हो गया, लेकिन क्यों?

http://kossovsky.net/index.php/2009/07/ie-memory-leak-jquery-garbage-collector/

और यह कोशिश करने का फैसला किया। आश्चर्यजनक रूप से, यह काम करता है! एसआईईवीई उन स्थानों में कोई रिसाव नहीं दिखाता है जिन्हें मैंने पहले पहचाना था और अर्थात् कार्य एक अधिक प्रबंधनीय स्मृति पदचिह्न बनाए रख रहा है।

मेरा सवाल है, यह क्यों काम करता है? jQuery.remove कॉल .removeChild, जो तत्व से छुटकारा पालना चाहिए, लेकिन स्पष्ट रूप से नहीं करता है। पैच इसके बजाय लक्ष्य तत्व को एक नए कचरा कलेक्टर div पर जोड़ता है, जिसे वह साफ़ करता है। हटाने की पैच विधि पूरी तरह से स्मृति को मुक्त क्यों करती है लेकिन jQuery का निकालना फ़ंक्शन नहीं करता है? मुझे यह समझने की उम्मीद है कि यह बड़े आवेदन में जांचने से पहले समाधान को संभवतः बेहतर बनाने के लिए क्यों काम करता है।

उत्तर

12

यह वर्तमान jQuery रिलीज (1.6.2) में .remove विधि है। ध्यान दें कि यह कॉल .cleanData:

// keepData is for internal use only--do not document 
    remove: function(selector, keepData) { 
     for (var i = 0, elem; (elem = this[i]) != null; i++) { 
      if (!selector || jQuery.filter(selector, [ elem ]).length) { 
       if (!keepData && elem.nodeType === 1) { 
        jQuery.cleanData(elem.getElementsByTagName("*")); 
        jQuery.cleanData([ elem ]); 
       } 

       if (elem.parentNode) { 
        elem.parentNode.removeChild(elem); 
       } 
      } 
     } 

     return this; 
    }, 

और .cleanData विधि है जो यह कहता है, जो एक टिकट नंबर का उल्लेख है और कथित तौर पर होने से बचाता है कि भयानक रिसाव (टिप्पणियों में से एक के अनुसार):

cleanData: function(elems) { 
     var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special, 
      deleteExpando = jQuery.support.deleteExpando; 

     for (var i = 0, elem; (elem = elems[i]) != null; i++) { 
      if (elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) { 
       continue; 
      } 

      id = elem[ jQuery.expando ]; 

      if (id) { 
       data = cache[ id ] && cache[ id ][ internalKey ]; 

       if (data && data.events) { 
        for (var type in data.events) { 
         if (special[ type ]) { 
          jQuery.event.remove(elem, type); 

         // This is a shortcut to avoid jQuery.event.remove's overhead 
         } else { 
          jQuery.removeEvent(elem, type, data.handle); 
         } 
        } 

        // Null the DOM reference to avoid IE6/7/8 leak (#7054) 
        if (data.handle) { 
         data.handle.elem = null; 
        } 
       } 

       if (deleteExpando) { 
        delete elem[ jQuery.expando ]; 

       } else if (elem.removeAttribute) { 
        elem.removeAttribute(jQuery.expando); 
       } 

       delete cache[ id ]; 
      } 
     } 
    } 

और यहाँ टिप्पणी में उल्लिखित टिकट है। जाहिरा तौर पर यह आठ महीने पहले तय किया गया था:

http://bugs.jquery.com/ticket/7054#comment:10

डेव Methvin के अनुसार समाधान करने के लिए सुनिश्चित करें कि एक ईवेंट हैंडलर में डोम तत्व रेफरी एक IE6/7/8 से बचने के लिए cleanData द्वारा हटा दिया जाता रहा है स्मृति रिसाव।

दूसरे शब्दों में, कोई भी नाम खांसी आईई खांसी स्मृति रिसाव का उल्लेख किए बिना, null अन्यथा कुछ कमाल ब्राउज़रों के लिए ईवेंट हैंडलर्स भीतर डोम तत्वों के लिए संदर्भ निर्धारित किया है।

discardElement (आपके लिंक से) तत्व को कंटेनर में सम्मिलित करता है, और उसके बाद कंटेनर खाली करता है, इस प्रकार उस तत्व के किसी भी संदर्भ को निरस्त करता है।

इसके साथ में, मैं jQuery को अपग्रेड करने का सुझाव दूंगा। जिस लेख को आप इंगित करते हैं वह 200 9 से है, और दो साल लगभग jQuery विकास के समय के चार सौ-अरब घंटे के बराबर है।

+0

दुर्भाग्य से मैं यथोचित ईवेंट हैंडलर्स की तलाश में पूरे codebase के माध्यम से नहीं कर सकते हैं:

अंत में, यहाँ इंटरनेट एक्सप्लोरर में रिसाव पैटर्न पर कुछ रोचक (और हास्यास्पद लंबे) पढ़ने है शून्य करने के लिए। यही कारण है कि यह हैकिश समाधान मुझे साजिश देता है। जहां तक ​​यह एक चांदी की बुलेट की तरह साबित हुआ है जिसे मैन्युअल रूप से हैंडलर को शून्य करने की आवश्यकता नहीं है। – JPRO

+0

@JPRO - नहीं ईवेंट हैंडलर्स, ईवेंट हैंडलर्स भीतर डोम तत्वों, और तुम क्या करने की जरूरत नहीं है कि अगर आप एक अधिक हाल के संस्करण में jQuery उन्नत करने के लिए तैयार हैं। – karim79

+0

निश्चित रूप से बुरा कोड समस्या में एक बड़ा योगदान रहा है, और मैं यह सब के माध्यम से जाने के लिए और इसे सही कर सकता है, लेकिन यह बहुत अधिक समय की तुलना में मैं इस कार्य के लिए आवंटित ले जाएगा। हम वर्तमान में jQuery 1.6.2 का उपयोग कर रहे हैं। मैंने कहा कि मुझे लगता है कि आपने सवाल का जवाब दिया है कि यह क्यों काम करता है (मैं खुद को एक ही निष्कर्ष पर आया लेकिन कुछ और इनपुट चाहता था)। जानकारी के लिए धन्यवाद! – JPRO

1

मैं सिद्धांत के लिए जा रहा हूं कि यह .NET कचरा संग्रह के समान है, जिसमें यह ढेर में पिन किए गए ऑब्जेक्ट्स पर निर्भर करता है।

आईई एक हटाए गए ऑब्जेक्ट के माता-पिता को पिन की तरह व्यवहार कर रहा है और हटाए गए ऑब्जेक्ट को ठीक से साफ़ नहीं कर रहा है।

हटाए गए आइटम को इस जेनरेट किए गए जीसी कंटेनर में ले जाने का कार्य मूल रूप से पिन को हटा रहा है क्योंकि आईई जानता है कि उस कंटेनर पर कुछ भी निर्भर नहीं है।

वैसे भी यह मेरी आंत महसूस कर रहा है।

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