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

Meggin Kearney
Meggin Kearney
Sofia Emelianova
Sofia Emelianova

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

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

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

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

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

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

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

उन ऑब्जेक्ट का कुल साइज़ जिन्हें ऐक्सेस किया जा सकता है.

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

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

स्नैपशॉट हटाएं

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

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

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

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

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

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

सारांश दृश्य

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

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

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

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

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

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

कंस्ट्रक्टर फ़िल्टर

खास जानकारी व्यू की मदद से, कंस्ट्रक्टर को फ़िल्टर करने के लिए, मेमोरी के गलत इस्तेमाल के सामान्य मामलों की जानकारी दी जाती है.

इन फ़िल्टर का इस्तेमाल करने के लिए, कार्रवाई बार में सबसे दाईं ओर मौजूद ड्रॉप-डाउन मेन्यू से, इनमें से कोई एक विकल्प चुनें:

  • सभी ऑब्जेक्ट: मौजूदा स्नैपशॉट से कैप्चर किए गए सभी ऑब्जेक्ट. डिफ़ॉल्ट रूप से सेट होता है.
  • स्नैपशॉट 1 से पहले तय किए गए ऑब्जेक्ट: ऐसे ऑब्जेक्ट जो पहला स्नैपशॉट लेने से पहले बनाए गए थे और मेमोरी में बने रहे.
  • स्नैपशॉट 1 और स्नैपशॉट 2 के बीच तय किए गए ऑब्जेक्ट: सबसे हाल के स्नैपशॉट और पिछले स्नैपशॉट के बीच के ऑब्जेक्ट के बीच का फ़र्क़ देखें. हर नया स्नैपशॉट, ड्रॉप-डाउन सूची में इस फ़िल्टर की बढ़ोतरी जोड़ देता है.
  • डुप्लीकेट स्ट्रिंग: ऐसी स्ट्रिंग वैल्यू जिन्हें मेमोरी में कई बार स्टोर किया गया है.
  • डिटैच किए गए नोड के ज़रिए बनाए रखे गए ऑब्जेक्ट: वे ऑब्जेक्ट जो इसलिए लाइव रखे जाते हैं, क्योंकि एक अलग किए गए DOM नोड में उनका रेफ़रंस दिया जाता है.
  • DevTools कंसोल के ज़रिए बनाए गए ऑब्जेक्ट: मेमोरी में रखे गए ऑब्जेक्ट, क्योंकि DevTools कंसोल के ज़रिए उनका मूल्यांकन या उनके साथ इंटरैक्ट किया गया था.

खास जानकारी वाले सेक्शन में खास एंट्री

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

  • पहले से मौजूद फ़ंक्शन, जैसे कि 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 खोलें और सेटिंग सेटिंग > एक्सपेरिमेंट > चेक_बॉक्स हीप स्नैपशॉट में अंदरूनी हिस्सों को दिखाने का विकल्प दिखाएं को चालू करें.
  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 का इंटरनल पॉइंटर होता है, जिसमें यह एक्ज़ीक्यूट होता है, ताकि यह उन वैरिएबल को ऐक्सेस कर सके. JavaScript से Context ऑब्जेक्ट सीधे तौर पर नहीं दिखते हैं, लेकिन उन पर आपका सीधा कंट्रोल होता है.

(system)

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

तुलना वाला व्यू

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

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

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

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

स्नैपशॉट 1 से तुलना की जा रही है.

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

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

व्यू में कई एंट्री पॉइंट हैं:

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

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

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

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

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

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

रिटेनर को अनदेखा करें

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

ड्रॉप-डाउन मेन्यू में 'इस रिटेनर को अनदेखा करें' विकल्प.

रिटेनर को छिपाने के लिए, राइट क्लिक करें और इस रिटेनर को अनदेखा करें को चुनें. दूरी कॉलम में, अनदेखा किए गए रिटेनर को ignored के तौर पर मार्क किया गया है. सभी रिटेनर को अनदेखा करना बंद करने के लिए, सबसे ऊपर कार्रवाई बार में playlist_remove अनदेखे किए गए रिटेनर को वापस लाएं पर क्लिक करें.

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

इकट्ठा किए गए हीप में किसी ऑब्जेक्ट को ढूंढने के लिए, 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;
}

क्लोज़र में नाम वाला फ़ंक्शन.

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

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

डॉक्यूमेंट ऑब्जेक्ट मॉडल (डीओएम) के लीक होने की जानकारी, आपकी उम्मीद से ज़्यादा बड़ी हो सकती है. यह उदाहरण देखें. #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 से जुड़ा पूरा ट्री दिखाया जाता है.

डीओएम सबट्री