43

jQuery में कुछ मानक मुद्दे या कोडिंग पैटर्न क्या हैं जो मेमोरी लीक का कारण बनते हैं?jQuery मेमोरी रिसाव पैटर्न और कारण


मैं ajax() कॉल या jsonp या StackOverflow पर डोम हटाने से संबंधित प्रश्नों की एक संख्या को देखा है। अधिकांश jQuery मेमोरी लीक प्रश्न विशिष्ट मुद्दों या ब्राउज़रों पर केंद्रित हैं और यह jQuery में मानक मेमोरी रिसाव पैटर्न की एक सूची होना अच्छा लगेगा।

उत्तर

28

मैं क्या समझ, जावास्क्रिप्ट में स्मृति प्रबंधन संदर्भ गिनती द्वारा पूरा किया है से - जबकि एक वस्तु के लिए एक संदर्भ अभी भी मौजूद है, यह पुनः आवंटित की जाती नहीं किया जाएगा। इसका मतलब है कि एक पेज एप्लिकेशन में मेमोरी रिसाव बनाना मामूली है, और जावा पृष्ठभूमि से आने वाले उपयोगों की यात्रा कर सकता है। यह JQuery के लिए विशिष्ट नहीं है। उदाहरण के लिए निम्नलिखित कोड डालें:

function MyObject = function(){ 
    var _this = this; 
    this.count = 0; 
    this.getAndIncrement = function(){ 
     _this.count++; 
     return _this.count; 
    } 
} 

for(var i = 0; i < 10000; i++){ 
    var obj = new MyObject(); 
    obj.getAndIncrement(); 
} 

यह जब तक आप स्मृति के उपयोग को देखने के सामान्य दिखेगा। "_this" पॉइंटर के कारण, पृष्ठ सक्रिय होने पर MyObject के उदाहरण कभी भी नष्ट नहीं किए जाते हैं (मुझे अधिकतम नाटकीय रूप से देखने के लिए अधिकतम मूल्य बढ़ाएं।)। (IE के पुराने संस्करणों में जब तक प्रोग्राम बाहर निकलता है तब तक उन्हें कभी भी हटाया नहीं जाता था।) चूंकि जावास्क्रिप्ट ऑब्जेक्ट्स फ्रेम के बीच साझा किए जा सकते हैं (मैं इसे अनुशंसा करने की अनुशंसा नहीं करता क्योंकि यह गंभीरता से स्वभावपूर्ण है।), ऐसे मामले हैं जहां एक आधुनिक ब्राउज़र जावास्क्रिप्ट में भी वस्तुओं के मुकाबले बहुत लंबे समय तक लटका सकते हैं।

function run(){ 
    var domObjects = $(".myClass"); 
    domObjects.click(function(){ 
     domObjects.addClass(".myOtherClass"); 
    }); 
} 

इस कोड domObject (और अपने सभी सामग्री) हमेशा के लिए पर पकड़ होगा, क्योंकि की: उदाहरण के लिए -

jQuery के संदर्भ में, संदर्भ अक्सर डोम खोज के भूमि के ऊपर बचाने के लिए जमा हो जाती है कॉलबैक फ़ंक्शन में इसका संदर्भ।

यदि jquery के लेखकों ने आंतरिक रूप से इस तरह के उदाहरणों को याद किया है, तो पुस्तकालय स्वयं ही रिसाव करेगा, लेकिन अक्सर यह ग्राहक कोड है।

function run(){ 
    var domObjects = $(".myClass"); 
    domObjects.click(function(){ 
     if(domObjects){ 
      domObjects.addClass(".myOtherClass"); 
      domObjects = null; 
     } 
    }); 
} 

या फिर देखने कर:

function run(){ 
    $(".myClass").click(function(){ 
     $(".myClass").addClass(".myOtherClass"); 
    }); 
} 

अंगूठे का एक अच्छा नियम होना है

दूसरे उदाहरण स्पष्ट सूचक जब यह नहीं रह गया है की आवश्यकता होती है समाशोधन द्वारा निर्धारित किया जा सकता है सावधान रहें जहां आप अपने कॉलबैक फ़ंक्शंस को परिभाषित करते हैं, और जहां संभव हो वहां बहुत अधिक घोंसले से बचें।

संपादित करें: के रूप में एरिक द्वारा टिप्पणी में बताया गया है, तो आप भी इस सूचक इस्तेमाल कर सकते हैं unnescessary डोम देखने से बचने के लिए:

function run(){ 
    $(".myClass").click(function(){ 
     $(this).addClass(".myOtherClass"); 
    }); 
} 
+2

यहाँ एक उदाहरण है: http://jsfiddle.net/qTu6y/8/ आप प्रोफाइलर में क्रोम के "हेपशॉट ले लो" का उपयोग यह देखने के लिए कर सकते हैं कि कोड के उस ब्लॉक के हर भाग में लगभग 20 एमबी रैम खाती है। (परीक्षण करते समय मैंने "स्क्रिप्ट पर क्रोम पर बहुत अधिक रैम त्रुटि का उपयोग किया" स्क्रिप्ट " – Raynos

+0

+1" उन लोगों में से जो "जावा पृष्ठभूमि से आ रहे हैं" ... और स्पष्ट स्पष्टीकरण के लिए। – Thimmayya

+1

$ (यह) .addClass पिछले मामले में प्रदर्शन के लिए बेहतर होगा क्योंकि 'यह' कोर जेएस डीओएम तत्व संग्रह का प्रतिनिधित्व करता है (जो कि JQuery ऑब्जेक्ट्स आमतौर पर एडाप्टर-शैली पैटर्न का उपयोग करके लपेट रहे हैं) और जेक्यू को नहीं करना होगा

15

मैं एक विरोधी पैटर्न यहाँ, योगदान देंगे जो है "मध्य श्रृंखला संदर्भ" रिसाव। आप के साथ सभी "एक jQuery वस्तु है

$(".message").addClass("unread").find(".author").addClass("noob"); 

कि श्रृंखला के अंत में:

jQuery की ताकत में से एक अपने श्रृंखलन एपीआई, आप को बदलने के लिए फिल्टर, और तत्वों में हेरफेर जारी रख सकते हैं जो है। संदेश। लेखक "तत्व, लेकिन कि ऑब्जेक्ट मूल" .message "तत्वों के साथ वापस और ऑब्जेक्ट को संदर्भित करता है। आप .end() विधि के माध्यम से उन तक पहुंचें और उन्हें करने के लिए कुछ कर सकते हैं:

$(".message") 
    .find(".author") 
    .addClass("prolific") 
    .end() 
    .addClass("unread"); 

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

तो उदाहरण के लिए, मान लें कि आप 2008 के कुछ ब्लॉग पोस्ट पर पढ़ते हैं कि $("a").find("b")$("a b") से "अधिक कुशल" था (भले ही यह माइक्रो-ऑप्टिमाइज़ेशन के बारे में सोचने योग्य नहीं है)। आप आप की जरूरत का फैसला एक पेज चौड़ा वैश्विक लेखकों की एक सूची धारण करने के लिए तो आप ऐसा करते हैं:

authors = $(".message").find(".author"); 

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

ध्यान दें कि लीक केवल तरीकों कि एक मौजूदा सेट से नई तत्वों का चयन के साथ हो सकता है, जैसे .find, .filter, .children आदि डॉक्स से संकेत मिलता है जब एक नई सेट दिया जाता है। बस एक श्रृंखलन एपीआई का उपयोग कर एक रिसाव का कारण नहीं है अगर श्रृंखला .css की तरह साधारण गैर छानने के तरीकों है, तो यह ठीक है:

authors = $(".message .author").addClass("prolific"); 
संबंधित मुद्दे