हीप स्नैपशॉट रिकॉर्ड करें

Meggin Kearney
Meggin Kearney
Sofia Emelianova
Sofia Emelianova

मेमोरी > प्रोफ़ाइल > हीप स्नैपशॉट का इस्तेमाल करके हीप स्नैपशॉट रिकॉर्ड करने और मेमोरी लीक ढूंढने का तरीका जानें.

हीप प्रोफ़ाइलर, आपके पेज के JavaScript ऑब्जेक्ट और उनसे जुड़े डीओएम नोड के ज़रिए मेमोरी डिस्ट्रिब्यूशन को दिखाता है. इसका इस्तेमाल JS हीप स्नैपशॉट लेने, मेमोरी ग्राफ़ का विश्लेषण करने, स्नैपशॉट की तुलना करने, और मेमोरी लीक का पता लगाने के लिए करें. ज़्यादा जानकारी के लिए, ऑब्जेक्ट को बनाए रखने वाली ट्री देखें.

स्‍नैपशॉट लें

हीप स्नैपशॉट लेने के लिए:

  1. आपको जिस पेज को प्रोफ़ाइल करना है, उस पर DevTools खोलें और मेमोरी पैनल पर जाएं.
  2. radio_button_checked हीप स्नैपशॉट प्रोफ़ाइलिंग टाइप चुनें. इसके बाद, JavaScript वीएम इंस्टेंस चुनें और स्नैपशॉट लें पर क्लिक करें.

चुना गया प्रोफ़ाइलिंग टाइप और JavaScript वीएम इंस्टेंस.

जब मेमोरी पैनल लोड होता है और स्नैपशॉट को पार्स करता है, तो यह HAP SNAPSHOTS सेक्शन में स्नैपशॉट के टाइटल के नीचे, ऐक्सेस किए जा सकने वाले JavaScript ऑब्जेक्ट का कुल साइज़ दिखाता है.

ऐक्सेस किए जा सकने वाले ऑब्जेक्ट का कुल साइज़.

स्नैपशॉट, मेमोरी ग्राफ़ के सिर्फ़ वे ऑब्जेक्ट दिखाते हैं जिन्हें ग्लोबल ऑब्जेक्ट से ऐक्सेस किया जा सकता है. स्नैपशॉट लेने की शुरुआत हमेशा कचरा हटाने के साथ होती है.

बिखरे हुए आइटम ऑब्जेक्ट का हीप स्नैपशॉट.

स्नैपशॉट साफ़ करें

सभी स्नैपशॉट हटाने के लिए, ब्लॉक करें सभी प्रोफ़ाइलें मिटाएं पर क्लिक करें:

सभी प्रोफ़ाइलें मिटाएं.

स्नैपशॉट देखें

अलग-अलग उद्देश्यों के लिए अलग-अलग नज़रिए से स्नैपशॉट की जांच करने के लिए, सबसे ऊपर मौजूद ड्रॉप-डाउन मेन्यू में से कोई एक व्यू चुनें:

देखें कॉन्टेंट मकसद
खास जानकारी कंस्ट्रक्टर के नाम के हिसाब से ग्रुप में बांटे गए ऑब्जेक्ट. इसकी मदद से, टाइप के हिसाब से ऑब्जेक्ट और उनकी मेमोरी के इस्तेमाल का पता लगाएं. डीओएम लीक को ट्रैक करने में मदद करता है.
Comparison दो स्नैपशॉट के बीच अंतर. इसका इस्तेमाल कार्रवाई के पहले और बाद के दो (या ज़्यादा) स्नैपशॉट की तुलना करने के लिए करें. खाली मेमोरी और रेफ़रंस काउंट में डेल्टा की जांच करके, मेमोरी लीक होने की वजह का पता लगाएं.
कंटेनमेंट हीप की सामग्री ऑब्जेक्ट स्ट्रक्चर का बेहतर व्यू देता है. साथ ही, ग्लोबल नेमस्पेस (विंडो) में रेफ़र किए गए ऑब्जेक्ट का विश्लेषण करने में मदद करता है, ताकि यह पता लगाया जा सके कि उन्हें किस चीज़ के आस-पास रखा जाता है. इसका इस्तेमाल, बंद किए जाने वाले ऑब्जेक्ट का विश्लेषण करने और छोटे लेवल पर अपने ऑब्जेक्ट के बारे में जानने के लिए करें.
आंकड़े मेमोरी के बंटवारे का पाई चार्ट कोड, स्ट्रिंग, JS कलेक्शन, टाइप किए गए अरे, और सिस्टम ऑब्जेक्ट के लिए असाइन किए गए, मेमोरी के हिस्सों का असल साइज़ देखें.

सबसे ऊपर मौजूद ड्रॉप-डाउन मेन्यू से चुना गया खास जानकारी वाला व्यू.

सारांश दृश्य

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

बड़े किए गए कंस्ट्रक्टर के साथ खास जानकारी वाला व्यू.

ऐसे कंस्ट्रक्टर को फ़िल्टर करने के लिए जो काम के नहीं हैं, खास जानकारी व्यू में सबसे ऊपर मौजूद क्लास फ़िल्टर में वह नाम टाइप करें जिसकी आपको जांच करनी है.

कंस्ट्रक्टर के नाम के बगल में दी गई संख्याएं, कंस्ट्रक्टर से बनाए गए ऑब्जेक्ट की कुल संख्या दिखाती हैं. खास जानकारी व्यू में ये कॉलम भी दिखते हैं:

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

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

जवाब में खास एंट्री

कंस्ट्रक्टर के हिसाब से ग्रुप में बांटने के साथ-साथ, खास जानकारी व्यू में ऑब्जेक्ट को इनके हिसाब से भी ग्रुप में बांटा जाता है:

  • Array या Object जैसे पहले से मौजूद फ़ंक्शन.
  • आपके कोड में तय किए गए फ़ंक्शन.
  • ऐसी खास कैटगरी जो कंस्ट्रक्टर के हिसाब से नहीं हैं.

कंस्ट्रक्टर की एंट्री.

(array)

इस कैटगरी में कई इंटरनल अरे जैसे ऑब्जेक्ट शामिल हैं. ये ऑब्जेक्ट, JavaScript में दिखने वाले ऑब्जेक्ट से सीधे तौर पर मेल नहीं खाते.

उदाहरण के लिए, JavaScript Array ऑब्जेक्ट का कॉन्टेंट, (object elements)[] नाम के सेकंडरी ऑब्जेक्ट में सेव किया जाता है, ताकि साइज़ आसानी से बदला जा सके. इसी तरह, JavaScript ऑब्जेक्ट में नाम वाली प्रॉपर्टी अक्सर, (object properties)[] नाम के सेकंडरी इंटरनल ऑब्जेक्ट में स्टोर की जाती हैं. ये ऑब्जेक्ट भी (array) कैटगरी में शामिल होते हैं.

(compiled code)

इस कैटगरी में अंदरूनी डेटा शामिल है, जिसकी ज़रूरत V8 को होती है, ताकि यह JavaScript या WebAssembly के तय किए गए फ़ंक्शन चला सके. हर फ़ंक्शन को अलग-अलग तरह से दिखाया जा सकता है. जैसे, छोटा, धीमा से लेकर बड़ा और तेज़ फ़ंक्शन.

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

(concatenated string)

जब V8 दो स्ट्रिंग को जोड़ता है, जैसे कि JavaScript + ऑपरेटर के साथ, तो यह अंदरूनी तौर पर नतीजे को "जोड़ी गई स्ट्रिंग" के तौर पर दिखा सकता है. इसे रोप का डेटा स्ट्रक्चर भी कहा जाता है.

दो सोर्स स्ट्रिंग के सभी वर्णों को किसी नई स्ट्रिंग में कॉपी करने के बजाय, V8, first और second नाम के अंदरूनी फ़ील्ड के साथ एक छोटा ऑब्जेक्ट असाइन करता है, जो दो सोर्स स्ट्रिंग की ओर इशारा करता है. इससे V8 टूल का इस्तेमाल करने पर, समय और मेमोरी बचती है. JavaScript कोड के हिसाब से, ये सामान्य स्ट्रिंग होती हैं और किसी दूसरी स्ट्रिंग की तरह ही काम करती हैं.

InternalNode

यह कैटगरी V8 के बाहर बांटे गए ऑब्जेक्ट दिखाती है, जैसे कि Blink के ज़रिए तय किए गए C++ ऑब्जेक्ट.

C++ क्लास के नाम देखने के लिए, Chrome for Testing का इस्तेमाल करें और ये काम करें:

  1. DevTools खोलें. इसके बाद, सेटिंग सेटिंग > प्रयोग > check_box को चालू करें. हीप स्नैपशॉट में इंटरनल दिखाने का विकल्प दिखाएं.
  2. मेमोरी पैनल खोलें, radio_button_checked हीप स्नैपशॉट चुनें. इसके बाद, radio_button_checked इंटरनल एक्सपोज़ करें (इसमें, लागू करने से जुड़ी अन्य खास जानकारी शामिल है) को चालू करें.
  3. उस समस्या को फिर से जनरेट करें जिसकी वजह से InternalNode, ज़्यादा मेमोरी सेव कर पाया.
  4. एक हीप स्नैपशॉट लें. इस स्नैपशॉट में, ऑब्जेक्ट में InternalNode के बजाय C++ क्लास के नाम हैं.
(object shape)

जैसा कि V8 में फ़ास्ट प्रॉपर्टी में बताया गया है, V8 छिपे हुए क्लास (या आकार) को ट्रैक करता है, ताकि एक जैसी प्रॉपर्टी वाले कई ऑब्जेक्ट को एक ही क्रम में दिखाया जा सके. इस कैटगरी में, system / Map नाम की छिपे हुए क्लास (JavaScript Map से संबंधित नहीं) और उनसे जुड़ा डेटा शामिल होता है.

(sliced string)

जब V8 को कोई सबस्ट्रिंग लेने की ज़रूरत होती है, जैसे कि जब JavaScript कोड String.prototype.substring() को कॉल करता है, तो V8 उसके पास मूल स्ट्रिंग से सभी काम के वर्णों को कॉपी करने के बजाय, स्लाइस की गई स्ट्रिंग ऑब्जेक्ट असाइन करने का विकल्प चुन सकता है. इस नए ऑब्जेक्ट में, ओरिजनल स्ट्रिंग का पॉइंटर होता है. साथ ही, यह बताता है कि ओरिजनल स्ट्रिंग के वर्णों की किस रेंज का इस्तेमाल करना है.

JavaScript कोड के हिसाब से, ये सामान्य स्ट्रिंग होती हैं और किसी दूसरी स्ट्रिंग की तरह ही काम करती हैं. अगर स्लाइस की गई स्ट्रिंग बहुत ज़्यादा मेमोरी बना रही है, तो हो सकता है कि प्रोग्राम ने समस्या 2869 को ट्रिगर किया हो. साथ ही, उसे स्लाइस की गई स्ट्रिंग को "समान" करने के लिए जान-बूझकर कदम उठाने पर फ़ायदा हो सकता है.

system / Context

system / Context टाइप के इंटरनल ऑब्जेक्ट में बंद होने पर, लोकल वैरिएबल शामिल होते हैं. यह एक JavaScript स्कोप है, जिसे नेस्ट किया गया फ़ंक्शन ऐक्सेस कर सकता है.

हर फ़ंक्शन इंस्टेंस में, Context के एक्ज़ीक्यूट होने के लिए एक इंटरनल पॉइंटर शामिल होता है, ताकि वह उन वैरिएबल को ऐक्सेस कर सके. भले ही Context ऑब्जेक्ट, JavaScript से सीधे तौर पर नहीं दिखते, लेकिन उन पर आपका सीधा कंट्रोल होता है.

(system)

इस कैटगरी में कई इंटरनल ऑब्जेक्ट हैं. इन्हें अब तक बेहतर तरीके से कैटगरी में नहीं रखा गया है.

तुलना का व्यू

तुलना व्यू में, कई स्नैपशॉट की तुलना एक-दूसरे से करके, लीक किए गए ऑब्जेक्ट को ढूंढा जा सकता है. उदाहरण के लिए, दस्तावेज़ को खोलने और बंद करने जैसी कोई कार्रवाई करना और उसे रिवर्स करना, अतिरिक्त ऑब्जेक्ट नहीं छोड़ना चाहिए.

यह पुष्टि करने के लिए कि किसी खास कार्रवाई के चलते लीक नहीं होता है:

  1. कोई कार्रवाई करने से पहले एक हीप स्नैपशॉट लें.
  2. कोई कार्रवाई करें. इसका मतलब है कि किसी पेज के साथ इस तरह इंटरैक्ट करें जिससे आपको लगे कि आपकी साइट पर उसका डेटा लीक हो रहा है.
  3. रिवर्स ऑपरेशन करें. इसका मतलब है कि उलटी बातचीत करें और इसे कई बार दोहराएं.
  4. एक और हीप स्नैपशॉट लें और इसके व्यू को तुलना में बदलें और इसकी तुलना स्नैपशॉट 1 से करें.

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

स्नैपशॉट 1 की तुलना में.

कंटेनमेंट व्यू

कंटेनमेंट व्यू, आपके ऐप्लिकेशन के ऑब्जेक्ट की बनावट का "बर्ड आई व्यू" होता है. इसकी मदद से, फ़ंक्शन को बंद किए जाने के बारे में जाना जा सकता है और वर्चुअल मशीन के इंटरनल ऑब्जेक्ट देखे जा सकते हैं. ये ऑब्जेक्ट, एक साथ आपके JavaScript ऑब्जेक्ट बनाते हैं. साथ ही, यह भी समझा जा सकता है कि आपका ऐप्लिकेशन, बहुत कम लेवल पर कितनी मेमोरी का इस्तेमाल करता है.

इस व्यू में कई एंट्री पॉइंट दिखते हैं:

  • DOMWindow ऑब्जेक्ट. JavaScript कोड के लिए ग्लोबल ऑब्जेक्ट.
  • GC रूट. GC रूट का इस्तेमाल वीएम का गार्बेज कलेक्टर करता है. GC रूट में पहले से मौजूद ऑब्जेक्ट मैप, सिंबल टेबल, वीएम थ्रेड स्टैक, कंपाइलेशन कैश, हैंडल स्कोप, और ग्लोबल हैंडल शामिल हो सकते हैं.
  • नेटिव ऑब्जेक्ट. ब्राउज़र ऑब्जेक्ट को JavaScript वर्चुअल मशीन में "पुश किया" जाता है, ताकि ऑटोमेशन की अनुमति दी जा सके. उदाहरण के लिए, डीओएम नोड और सीएसएस नियम.

कंटेनमेंट व्यू.

रिटेनर सेक्शन

मेमोरी पैनल में सबसे नीचे मौजूद रिटेनर सेक्शन, ऐसे ऑब्जेक्ट दिखाता है जो व्यू में चुने गए ऑब्जेक्ट पर ले जाते हैं.

रिटेनर सेक्शन.

इस उदाहरण में, चुनी गई स्ट्रिंग को Item इंस्टेंस की x प्रॉपर्टी के ज़रिए बनाए रखा जाता है.

कोई खास ऑब्जेक्ट ढूंढना

इकट्ठा किए गए हीप में किसी ऑब्जेक्ट को ढूंढने के लिए, Ctrl + F का इस्तेमाल करें और ऑब्जेक्ट आईडी डालें.

बंद मोड के बीच फ़र्क़ करने के लिए, फ़ंक्शन को नाम दें

इससे फ़ंक्शन को नाम देने में काफ़ी मदद मिलती है, ताकि आप स्नैपशॉट में बंद होने वाले खातों के बीच अंतर कर सकें.

उदाहरण के लिए, यहां दिया गया कोड, नाम वाले फ़ंक्शन का इस्तेमाल नहीं करता:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function() { // this is NOT a named function
    return largeStr;
  };

  return lC;
}

हालांकि, इस उदाहरण में यह नीति मौजूद है:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function lC() { // this IS a named function
    return largeStr;
  };

  return lC;
}

बंद होने वाले फ़ंक्शन में, नाम वाला फ़ंक्शन मौजूद है.

डीओएम लीक का पता लगाना

हीप प्रोफ़ाइलर में, ब्राउज़र के नेटिव ऑब्जेक्ट (DOM नोड और सीएसएस नियम) और JavaScript ऑब्जेक्ट के बीच दोतरफ़ा डिपेंडेंसी दिखाने की सुविधा होती है. इससे हमें उन लीक का पता लगाने में मदद मिलती है जो पूरी तरह नहीं दिखते. ऐसा इसलिए है, क्योंकि इन डिटैच किए गए डीओएम सबट्री को भूलने की वजह से, ये सब-ट्री आस-पास हो रही हैं.

DOM लीक आपकी उम्मीद से ज़्यादा हो सकते हैं. नीचे दिया गया उदाहरण देखें. #tree का कचरा कब इकट्ठा किया जाता है?

  var select = document.querySelector;
  var treeRef = select("#tree");
  var leafRef = select("#leaf");
  var body = select("body");

  body.removeChild(treeRef);

  //#tree can't be GC yet due to treeRef
  treeRef = null;

  //#tree can't be GC yet due to indirect
  //reference from leafRef

  leafRef = null;
  //#NOW #tree can be garbage collected

#leaf अपने पैरंट (parentNode) का रेफ़रंस देता है और बार-बार #tree तक करता है. इसलिए, leafRef के शून्य होने पर ही, #tree में मौजूद पूरा ट्री, GC का उम्मीदवार होता है.

DOM सबट्री