मेमोरी का इस्तेमाल करके हीप स्नैपशॉट रिकॉर्ड करने का तरीका जानें > प्रोफ़ाइल > हीप स्नैपशॉट और मेमोरी लीक को ढूंढें.
हीप प्रोफ़ाइलर से, आपको अपने पेज के JavaScript ऑब्जेक्ट और उनसे जुड़े डीओएम नोड के बीच मेमोरी डिस्ट्रिब्यूशन का पता चलता है. इसका इस्तेमाल JS हीप स्नैपशॉट लेने, मेमोरी ग्राफ़ का विश्लेषण करने, स्नैपशॉट की तुलना करने, और मेमोरी लीक का पता लगाने के लिए करें. ज़्यादा जानकारी के लिए, ऑब्जेक्ट बनाए रखने वाले ट्री देखें.
स्नैपशॉट लें
हीप स्नैपशॉट लेने के लिए:
- जिस पेज को प्रोफ़ाइल बनाना है उस पर DevTools खोलें और मेमोरी पैनल पर जाएं.
- Heap स्नैपशॉट प्रोफ़ाइलिंग टाइप चुनें. इसके बाद, कोई JavaScript वीएम इंस्टेंस चुनें और स्नैपशॉट लें पर क्लिक करें.
जब मेमोरी पैनल, स्नैपशॉट को लोड और पार्स करता है, तो यह HAPI SNAPSHOTS सेक्शन में स्नैपशॉट के टाइटल के नीचे, ऐक्सेस किए जा सकने वाले JavaScript ऑब्जेक्ट का कुल साइज़ दिखाता है.
स्नैपशॉट में, मेमोरी ग्राफ़ से सिर्फ़ वे ऑब्जेक्ट दिखते हैं जो ग्लोबल ऑब्जेक्ट से ऐक्सेस किए जा सकते हैं. स्नैपशॉट लेने की शुरुआत हमेशा कूड़ा इकट्ठा करने से होती है.
स्नैपशॉट हटाएं
सभी स्नैपशॉट हटाने के लिए,
सभी प्रोफ़ाइल मिटाएं पर क्लिक करें:स्नैपशॉट देखें
अलग-अलग मकसद से स्नैपशॉट लेने के लिए, सबसे ऊपर मौजूद ड्रॉप-डाउन मेन्यू में से कोई एक व्यू चुनें:
देखें | सामग्री | मकसद |
---|---|---|
खास जानकारी | कंस्ट्रक्टर के नाम के हिसाब से ग्रुप में बांटे गए ऑब्जेक्ट. | इसका इस्तेमाल करके, अलग-अलग तरह के ऑब्जेक्ट और उनकी मेमोरी के इस्तेमाल का पता लगाया जाता है. DOM से लीक होने वाले डेटा को ट्रैक करने में मददगार. |
Comparison | दो स्नैपशॉट के बीच अंतर. | इसका इस्तेमाल किसी कार्रवाई से पहले और बाद में दो (या ज़्यादा) स्नैपशॉट की तुलना करने के लिए करें. फ़्री की गई मेमोरी और रेफ़रंस फ़ाइलों की संख्या में डेल्टा की जांच करके, मेमोरी लीक होने की वजह और मौजूदगी की पुष्टि करें. |
कटेनमेंट | हीप कॉन्टेंट | इससे ऑब्जेक्ट के स्ट्रक्चर को बेहतर तरीके से देखा जा सकता है. साथ ही, ग्लोबल नेमस्पेस (विंडो) में रेफ़र किए गए ऑब्जेक्ट का विश्लेषण करके, यह पता लगाया जा सकता है कि वे ऑब्जेक्ट क्यों मौजूद हैं. इसका इस्तेमाल, बंद होने का विश्लेषण करने और अपने ऑब्जेक्ट के बारे में लो लेवल पर जाने के लिए करें. |
आंकड़े | मेमोरी के बंटवारे का पाई चार्ट | कोड, स्ट्रिंग, JS कैटगरी, टाइप किए गए अरे, और सिस्टम ऑब्जेक्ट के लिए असाइन किए गए मेमोरी पार्ट्स का रियलेटिव साइज़ देखें. |
सारांश दृश्य
शुरुआत में, खास जानकारी व्यू में हीप स्नैपशॉट खुलता है. इसमें एक कॉलम में कंस्ट्रक्टर की सूची होती है. कंस्ट्रक्टर के ज़रिए, उन ऑब्जेक्ट को देखा जा सकता है जिन्हें वे इंस्टैंशिएट करते हैं.
बिना काम के कंस्ट्रक्टर को फ़िल्टर करने के लिए, खास जानकारी व्यू में सबसे ऊपर मौजूद क्लास फ़िल्टर में कोई ऐसा नाम टाइप करें जिसकी जांच आपको करनी है.
कंस्ट्रक्टर के नाम के बगल में मौजूद नंबर, कंस्ट्रक्टर की मदद से बनाए गए ऑब्जेक्ट की कुल संख्या के बारे में बताते हैं. खास जानकारी व्यू में ये कॉलम भी दिखते हैं:
- दूरी, नोड के सबसे छोटे सामान्य पाथ का इस्तेमाल करके रूट की दूरी दिखाता है.
- शैलो साइज़, किसी खास कन्स्ट्रक्टर से बनाए गए सभी ऑब्जेक्ट के शैलो साइज़ का कुल योग दिखाता है. शैलो साइज़, किसी ऑब्जेक्ट के पास मौजूद मेमोरी का साइज़ होता है. आम तौर पर, अरे और स्ट्रिंग का साइज़ शैलो होता है. ऑब्जेक्ट के साइज़ भी देखें.
- बनाए गए साइज़ से पता चलता है कि ऑब्जेक्ट के एक जैसे सेट के लिए, सबसे ज़्यादा साइज़ कितना है. 'सेव किया गया साइज़', उस मेमोरी का साइज़ होता है जिसे किसी ऑब्जेक्ट को मिटाकर, खाली किया जा सकता है. ऐसा करने से, उस ऑब्जेक्ट को ऐक्सेस नहीं किया जा सकेगा. ऑब्जेक्ट के साइज़ भी देखें.
जब किसी कंस्ट्रक्टर को बड़ा किया जाता है, तो खास जानकारी व्यू में, आपको इसके सभी इंस्टेंस दिखते हैं. हर इंस्टेंस के लिए, उससे जुड़े कॉलम में उसके शैलो और रिटेंन किए गए साइज़ का ब्रेकडाउन दिखता है. @
वर्ण के बाद की संख्या, ऑब्जेक्ट का यूनीक आईडी होती है. इससे हर ऑब्जेक्ट के आधार पर हीप स्नैपशॉट की तुलना की जा सकती है.
कंस्ट्रक्टर फ़िल्टर
खास जानकारी व्यू की मदद से, कंस्ट्रक्टर को फ़िल्टर करने के लिए, मेमोरी के गलत इस्तेमाल के सामान्य मामलों की जानकारी दी जाती है.
इन फ़िल्टर का इस्तेमाल करने के लिए, कार्रवाई बार में सबसे दाईं ओर मौजूद ड्रॉप-डाउन मेन्यू से, इनमें से कोई एक विकल्प चुनें:
- सभी ऑब्जेक्ट: मौजूदा स्नैपशॉट से कैप्चर किए गए सभी ऑब्जेक्ट. डिफ़ॉल्ट रूप से सेट होता है.
- स्नैपशॉट 1 से पहले तय किए गए ऑब्जेक्ट: ऐसे ऑब्जेक्ट जो पहला स्नैपशॉट लेने से पहले बनाए गए थे और मेमोरी में बने रहे.
- स्नैपशॉट 1 और स्नैपशॉट 2 के बीच तय किए गए ऑब्जेक्ट: सबसे हाल के स्नैपशॉट और पिछले स्नैपशॉट के बीच के ऑब्जेक्ट के बीच का फ़र्क़ देखें. हर नए स्नैपशॉट से, ड्रॉप-डाउन सूची में इस फ़िल्टर की संख्या बढ़ जाती है.
- डुप्लीकेट स्ट्रिंग: ऐसी स्ट्रिंग वैल्यू जिन्हें मेमोरी में कई बार स्टोर किया गया है.
- डिटैच किए गए नोड की मदद से सेव किए गए ऑब्जेक्ट: ऐसे ऑब्जेक्ट जिन्हें सेव रखा जाता है, क्योंकि डिटैच किया गया डीओएम नोड उनका रेफ़रंस देता है.
- DevTools कंसोल की मदद से सेव किए गए ऑब्जेक्ट: ये ऐसे ऑब्जेक्ट होते हैं जिन्हें मेमोरी में इसलिए सेव किया जाता है, क्योंकि DevTools कंसोल की मदद से उनका आकलन किया गया है या उनसे इंटरैक्ट किया गया है.
खास जानकारी वाले सेक्शन में खास एंट्री
कंस्ट्रक्टर के हिसाब से ग्रुप करने के अलावा, खास जानकारी व्यू, ऑब्जेक्ट को इनके आधार पर भी ग्रुप में रखता है:
- पहले से मौजूद फ़ंक्शन, जैसे कि
Array
याObject
. - अपने टैग के हिसाब से ग्रुप किए गए एचटीएमएल एलिमेंट, उदाहरण के लिए,
<div>
,<a>
,<img>
वगैरह. - वे फ़ंक्शन जिन्हें आपने अपने कोड में तय किया है.
- ऐसी खास कैटगरी जो कंस्ट्रक्टर पर आधारित नहीं हैं.
(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 का इस्तेमाल करें और ये काम करें:
- DevTools खोलें और सेटिंग चालू करें > एक्सपेरिमेंट > हीप स्नैपशॉट में अंदरूनी हिस्सों को दिखाने का विकल्प दिखाएं.
- मेमोरी पैनल खोलें. इसके बाद, हीप स्नैपशॉट चुनें और इंटरनल डेटा दिखाएं (इसमें, इसे इस्तेमाल करने से जुड़ी अन्य ज़रूरी जानकारी शामिल है) को चालू करें.
- वह समस्या फिर से करें जिसकी वजह से
InternalNode
ने बहुत ज़्यादा मेमोरी बनाए रखी है. - एक हीप स्नैपशॉट लें. इस स्नैपशॉट में, ऑब्जेक्ट में
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.
तुलना व्यू, दो स्नैपशॉट के बीच अंतर दिखाता है. कुल वैल्यू को बड़ा करते समय एंट्री, जोड़े और मिटाए गए ऑब्जेक्ट के इंस्टेंस दिखाए गए हैं:
कंटेनमेंट व्यू
कंटेनमेंट व्यू, आपके ऐप्लिकेशन के ऑब्जेक्ट स्ट्रक्चर का "विहंगम दृश्य" होता है. इसकी मदद से, फ़ंक्शन के बंद होने के बारे में जानकारी हासिल की जा सकती है. साथ ही, वर्चुअल मशीन के ऐसे ऑब्जेक्ट देखे जा सकते हैं जो साथ मिलकर आपके JavaScript ऑब्जेक्ट बनाते हैं. साथ ही, इससे यह भी समझा जा सकता है कि आपका ऐप्लिकेशन, बहुत कम लेवल पर कितनी मेमोरी का इस्तेमाल करता है.
व्यू में कई एंट्री पॉइंट हैं:
- DOMWindow ऑब्जेक्ट. JavaScript कोड के लिए ग्लोबल ऑब्जेक्ट.
- जीसी रूट. जीसी रूट, जिनका इस्तेमाल वर्चुअल मशीन (वीएम) का गार्बेज कलेक्टर करता है. जीसी रूट में, पहले से मौजूद ऑब्जेक्ट मैप, सिंबल टेबल, VM थ्रेड स्टैक, कंपाइलेशन कैश मेमोरी, हैंडल स्कोप, और ग्लोबल हैंडल शामिल हो सकते हैं.
- नेटिव ऑब्जेक्ट. ब्राउज़र ऑब्जेक्ट "पुश किए गए" JavaScript वर्चुअल मशीन में जोड़ा जा सकता है, ताकि ऑटोमेशन की अनुमति दी जा सके. उदाहरण के लिए, DOM नोड और सीएसएस नियम.
रिटेनर सेक्शन
मेमोरी पैनल के सबसे नीचे मौजूद रिटेनर सेक्शन में वे ऑब्जेक्ट दिखते हैं जो व्यू में चुने गए ऑब्जेक्ट पर ले जाते हैं. जब आंकड़ों को छोड़कर किसी भी व्यू में कोई दूसरा ऑब्जेक्ट चुना जाता है, तब मेमोरी पैनल रिटेनर सेक्शन को अपडेट कर देता है.
इस उदाहरण में, चुनी गई स्ट्रिंग को Item
इंस्टेंस की x
प्रॉपर्टी में सेव किया जाता है.
रिटेनर को अनदेखा करें
रिटेनर को छिपाया जा सकता है, ताकि यह पता लगाया जा सके कि चुने गए ऑब्जेक्ट में कौनसा ऑब्जेक्ट बना रहेगा. इस विकल्प के साथ, आपको पहले इस रिटेनर को कोड से हटाने और हीप स्नैपशॉट को फिर से लेने की ज़रूरत नहीं है.
रिटेनर को छिपाने के लिए, राइट क्लिक करें और इस रिटेनर को अनदेखा करें को चुनें. दूरी कॉलम में, अनदेखा किए गए रिटेनर को ignored
के तौर पर मार्क किया गया है. सभी रिटेनर को अनदेखा करना बंद करने के लिए, सबसे ऊपर कार्रवाई बार में अनदेखे किए गए रिटेनर को वापस लाएं पर क्लिक करें.
कोई खास ऑब्जेक्ट ढूंढना
इकट्ठा किए गए हीप में किसी ऑब्जेक्ट को ढूंढने के लिए, 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
के नीचे का पूरा ट्री, GC के लिए उम्मीदवार होता है.