इस सेक्शन में, मेमोरी विश्लेषण में इस्तेमाल होने वाले सामान्य शब्दों के बारे में बताया गया है. यह सेक्शन, अलग-अलग भाषाओं के लिए, मेमोरी प्रोफ़ाइलिंग टूल पर लागू होता है.
यहां बताए गए शब्द और सिद्धांत, Chrome DevTools के Heap Profiler से जुड़े हैं. अगर आपने कभी Java, .NET या किसी अन्य मेमोरी प्रोफ़ाइलर के साथ काम किया है, तो यह आपके लिए रीफ़्रेशर हो सकता है.
ऑब्जेक्ट के साइज़
मेमोरी को प्राइमटिव टाइप (जैसे, संख्याएं और स्ट्रिंग) और ऑब्जेक्ट (असोसिएटिव ऐरे) वाले ग्राफ़ के तौर पर देखें. इसे विज़ुअल तौर पर, एक ग्राफ़ के तौर पर दिखाया जा सकता है. इसमें कई पॉइंट एक-दूसरे से जुड़े होते हैं. जैसे:
कोई ऑब्जेक्ट, मेमोरी को दो तरीकों से सेव कर सकता है:
- सीधे ऑब्जेक्ट से.
- अन्य ऑब्जेक्ट के रेफ़रंस को छिपाकर, ताकि उन ऑब्जेक्ट को गै़रबेज कलेक्टर (छोटे में GC) अपने-आप न हटा सके.
DevTools में Heap Profiler का इस्तेमाल करते समय, आपको जानकारी के कुछ अलग-अलग कॉलम दिख सकते हैं. Heap Profiler, मेमोरी पैनल में मिली मेमोरी से जुड़ी समस्याओं की जांच करने वाला टूल है. इनमें से दो साइज़, शैलो साइज़ और रिटेंन किया गया साइज़, सबसे ज़्यादा इस्तेमाल किए जाते हैं. हालांकि, इनसे क्या पता चलता है?
शैलो साइज़
यह मेमोरी का वह साइज़ होता है जो ऑब्जेक्ट के पास होता है.
आम तौर पर, JavaScript ऑब्जेक्ट के ब्यौरे और तुरंत वैल्यू को स्टोर करने के लिए, कुछ मेमोरी रिज़र्व की जाती है. आम तौर पर, सिर्फ़ ऐरे और स्ट्रिंग का साइज़ छोटा हो सकता है. हालांकि, स्ट्रिंग और बाहरी कलेक्शन का मुख्य स्टोरेज अक्सर रेंडरर मेमोरी में होता है. साथ ही, JavaScript ढेर पर सिर्फ़ एक छोटा रैपर ऑब्जेक्ट दिखाया जाता है.
रेंडरर मेमोरी, उस प्रोसेस की सभी मेमोरी होती है जिसमें जांचे गए पेज को रेंडर किया जाता है: पेज की नेटिव मेमोरी + JS के लिए पेज की हेप मेमोरी + पेज से शुरू किए गए सभी वर्कर्स की हेप मेमोरी. हालांकि, अपने-आप ग़ैर-ज़रूरी आइटम हटाने की प्रोसेस से, अन्य आइटम को हटाने से रोककर, एक छोटा आइटम भी बहुत ज़्यादा मेमोरी का इस्तेमाल कर सकता है.
रिटेन किया गया साइज़
यह मेमोरी का वह साइज़ होता है जो ऑब्जेक्ट के मिट जाने के बाद, उस पर निर्भर उन ऑब्जेक्ट के साथ खाली हो जाती है जिन्हें GC रूट से ऐक्सेस नहीं किया जा सकता.
GC रूट, हैंडल से बने होते हैं. ये हैंडल, V8 के बाहर मौजूद किसी JavaScript ऑब्जेक्ट से नेटिव कोड का रेफ़रंस बनाते समय बनाए जाते हैं. ये हैंडल, लोकल या ग्लोबल हो सकते हैं. ऐसे सभी हैंडल, GC रूट > हैंडल का दायरा और GC रूट > ग्लोबल हैंडल में मौजूद, हेप स्नैपशॉट में देखे जा सकते हैं. ब्राउज़र में लागू करने के बारे में जानकारी दिए बिना, इस दस्तावेज़ में हैंडल के बारे में बताना भ्रम पैदा कर सकता है. आपको GC रूट और हैंडल, दोनों के बारे में चिंता करने की ज़रूरत नहीं है.
कई इंटरनल जीसी रूट हैं, जिनमें से ज़्यादातर उपयोगकर्ताओं के लिए दिलचस्प नहीं हैं. ऐप्लिकेशन के हिसाब से, ये तरह के रूट होते हैं:
- विंडो ग्लोबल ऑब्जेक्ट (हर iframe में). ढेर के स्नैपशॉट में एक 'डिस्टेंस फ़ील्ड' होता है. यह विंडो से सबसे छोटे रिटेनिंग पाथ पर मौजूद प्रॉपर्टी रेफ़रंस की संख्या होती है.
- दस्तावेज़ का डीओएम ट्री, जिसमें दस्तावेज़ को ट्रैवर्स करके पहुंचा जा सकने वाले सभी नेटिव डीओएम नोड शामिल होते हैं. हो सकता है कि इनमें से सभी में JS रैपर न हों. हालांकि, अगर इनमें JS रैपर हैं, तो दस्तावेज़ के मौजूद होने तक रैपर भी मौजूद रहेंगे.
- कभी-कभी, डीबगर कॉन्टेक्स्ट और DevTools कंसोल (उदाहरण के लिए, कंसोल के आकलन के बाद) ऑब्जेक्ट को सेव कर सकते हैं. डीबगर में साफ़ कंसोल और कोई चालू ब्रेकपॉइंट के साथ हीप स्नैपशॉट बनाएं.
मेमोरी ग्राफ़, रूट से शुरू होता है. यह ब्राउज़र का window
ऑब्जेक्ट या Node.js मॉड्यूल का Global
ऑब्जेक्ट हो सकता है. आपके पास यह कंट्रोल करने का विकल्प नहीं होता कि इस रूट ऑब्जेक्ट को GC कैसे किया जाए.
जो भी चीज़ रूट से ऐक्सेस नहीं की जा सकती उसे GC कर दिया जाता है.
ऑब्जेक्ट के लिए ट्री
हेप, आपस में जुड़े ऑब्जेक्ट का नेटवर्क होता है. गणित के क्षेत्र में, इस स्ट्रक्चर को ग्राफ़ या मेमोरी ग्राफ़ कहा जाता है. ग्राफ़, एज से जुड़े नोड से बनाया जाता है. इन दोनों को लेबल दिया जाता है.
- नोड (या ऑब्जेक्ट) को उस कन्स्ट्रक्टर फ़ंक्शन के नाम का इस्तेमाल करके लेबल किया जाता है जिसका इस्तेमाल उन्हें बनाने के लिए किया गया था.
- एज को प्रॉपर्टी के नामों का इस्तेमाल करके लेबल किया जाता है.
Heap Profiler का इस्तेमाल करके प्रोफ़ाइल रिकॉर्ड करने का तरीका जानें. यहां दी गई Heap Profiler रिकॉर्डिंग में, कुछ दिलचस्प चीज़ें देखी जा सकती हैं. जैसे, दूरी: जीसी रूट से दूरी. अगर एक ही तरह के ज़्यादातर ऑब्जेक्ट एक ही दूरी पर हैं और कुछ ऑब्जेक्ट ज़्यादा दूरी पर हैं, तो इसकी जांच की जानी चाहिए.
Dominators
डोमिनेटर ऑब्जेक्ट, ट्री स्ट्रक्चर में होते हैं, क्योंकि हर ऑब्जेक्ट में सिर्फ़ एक डोमिनेटर होता है. किसी ऑब्जेक्ट के डामिनेटर में, उस ऑब्जेक्ट के डायरेक्ट रेफ़रंस मौजूद नहीं हो सकते जिसे वह कंट्रोल करता है. इसका मतलब है कि डामिनेटर का ट्री, ग्राफ़ का स्पैनिंग ट्री नहीं है.
इस डायग्राम में:
- नोड 1, नोड 2 पर हावी है
- नोड 2, नोड 3, 4, और 6 पर हावी है
- नोड 3, नोड 5 पर हावी है
- नोड 5, नोड 8 पर हावी है
- नोड 6, नोड 7 पर हावी है
नीचे दिए गए उदाहरण में, नोड #3
, #10
का डॉमिनेटर है. हालांकि, जीसी से #10
तक के हर आसान पाथ में #7
भी मौजूद है. इसलिए, कोई ऑब्जेक्ट B, ऑब्जेक्ट A का डोमिनेटर होता है, अगर B, रूट से ऑब्जेक्ट A तक के हर आसान पाथ में मौजूद होता है.
V8 के बारे में खास जानकारी
मेमोरी की प्रोफ़ाइल बनाते समय, यह समझना मददगार होता है कि हीप स्नैपशॉट एक खास तरह से क्यों दिखते हैं. इस सेक्शन में, मेमोरी से जुड़े कुछ विषयों के बारे में बताया गया है. इनमें खास तौर पर, V8 JavaScript वर्चुअल मशीन (V8 VM या VM) के बारे में बताया गया है.
JavaScript ऑब्जेक्ट का रेप्रज़ेंटेशन
प्राइमटिव टाइप तीन तरह के होते हैं:
- संख्याएं (उदाहरण के लिए, 3.14159..)
- बूलियन (सही या गलत)
- स्ट्रिंग (उदाहरण के लिए, 'वर्नर हाइज़ेनबर्ग')
ये अन्य वैल्यू का रेफ़रंस नहीं दे सकते और हमेशा लीफ़ या टर्मिनेट करने वाले नोड होते हैं.
नंबर को इनमें से किसी भी तरह से सेव किया जा सकता है:
- छोटे इंटेजर (एसएमआई) कहे जाने वाले, 31-बिट के इंस्टैंट इंटेजर वैल्यू या
- हीप नंबर के तौर पर जाने जाने वाले हीप ऑब्जेक्ट. डबल जैसी वैल्यू को स्टोर करने के लिए, हीप नंबर का इस्तेमाल किया जाता है. ऐसा तब भी किया जाता है, जब किसी वैल्यू को बॉक्स में रखना ज़रूरी हो. जैसे, उस पर प्रॉपर्टी सेट करना.
स्ट्रिंग को इनमें से किसी एक में सेव किया जा सकता है:
- वीएम हेप या
- रेंडरर की मेमोरी में बाहर से. रैपर ऑब्जेक्ट बनाया जाता है और इसका इस्तेमाल, बाहरी स्टोरेज को ऐक्सेस करने के लिए किया जाता है. उदाहरण के लिए, वेब से मिलने वाले स्क्रिप्ट सोर्स और अन्य कॉन्टेंट को, VM ढेर पर कॉपी करने के बजाय स्टोर किया जाता है.
नए JavaScript ऑब्जेक्ट के लिए मेमोरी, खास JavaScript हीप (या VM हीप) से ऐलोकेट की जाती है. इन ऑब्जेक्ट को V8 के कचरा इकट्ठा करने वाले टूल से मैनेज किया जाता है. इसलिए, जब तक इनका कम से कम एक रेफ़रंस मौजूद रहेगा, तब तक ये ऑब्जेक्ट मौजूद रहेंगे.
नेटिव ऑब्जेक्ट वे सभी चीज़ें हैं जो JavaScript ढेर में नहीं होतीं. हीप ऑब्जेक्ट के मुकाबले, नेटिव ऑब्जेक्ट को V8 गै़रबेज कलेक्टर अपने पूरे लाइफ़टाइम के दौरान मैनेज नहीं करता. साथ ही, इसे सिर्फ़ JavaScript के रैपर ऑब्जेक्ट का इस्तेमाल करके, JavaScript से ऐक्सेस किया जा सकता है.
Cons स्ट्रिंग एक ऑब्जेक्ट है, जिसमें स्ट्रिंग के जोड़े होते हैं. इन स्ट्रिंग को स्टोर करने के बाद, उन्हें आपस में जोड़ दिया जाता है. यह स्ट्रिंग, स्ट्रिंग को आपस में जोड़ने की प्रोसेस का नतीजा होती है. cons स्ट्रिंग के कॉन्टेंट को सिर्फ़ ज़रूरत पड़ने पर जोड़ा जाता है. उदाहरण के लिए, जब जॉइन की गई स्ट्रिंग की सबस्ट्रिंग बनानी हो.
उदाहरण के लिए, a और b को जोड़ने पर, आपको एक स्ट्रिंग (a, b) मिलती है, जो जोड़ने के नतीजे को दिखाती है. अगर बाद में उस नतीजे के साथ d को जोड़ा जाता है, तो आपको एक और कॉन्स स्ट्रिंग ((a, b), d) मिलती है.
कलेक्शन - कलेक्शन, अंकों वाली कुंजियों वाला एक ऑब्जेक्ट होता है. इनका इस्तेमाल, V8 VM में ज़्यादा डेटा स्टोर करने के लिए किया जाता है. डिक्शनरी की तरह इस्तेमाल किए जाने वाले की-वैल्यू पेयर के सेट का बैक अप, ऐरे से लिया जाता है.
आम तौर पर, JavaScript ऑब्जेक्ट, स्टोर करने के लिए इस्तेमाल किए जाने वाले दो तरह के कलेक्शन में से एक हो सकता है:
- नाम वाली प्रॉपर्टी, और
- अंकों वाले एलिमेंट
जिन मामलों में प्रॉपर्टी की संख्या बहुत कम होती है उन्हें JavaScript ऑब्जेक्ट में ही स्टोर किया जा सकता है.
मैप-यह एक ऐसा ऑब्जेक्ट है जो ऑब्जेक्ट के टाइप और उसके लेआउट के बारे में बताता है. उदाहरण के लिए, प्रॉपर्टी को तेज़ी से ऐक्सेस करने के लिए, मैप का इस्तेमाल करके ऑब्जेक्ट की लागू हैरारकी के बारे में बताया जाता है.
ऑब्जेक्ट ग्रुप
हर नेटिव ऑब्जेक्ट ग्रुप, ऐसे ऑब्जेक्ट से बना होता है जो एक-दूसरे के रेफ़रंस रखते हैं. उदाहरण के लिए, एक डीओएम सबट्री पर विचार करें, जहां हर नोड में अपने पैरंट और अगले चाइल्ड और अगले सिबलिंग के लिंक होते हैं. इससे कनेक्टेड ग्राफ़ बनता है. ध्यान दें कि नेटिव ऑब्जेक्ट, JavaScript ढेर में नहीं दिखाए जाते हैं. इसलिए, उनका साइज़ शून्य होता है. इसके बजाय, रैपर ऑब्जेक्ट बनाए जाते हैं.
हर रैपर ऑब्जेक्ट में, उससे जुड़े नेटिव ऑब्जेक्ट का रेफ़रंस होता है, ताकि उस पर निर्देशों को रीडायरेक्ट किया जा सके. ऑब्जेक्ट ग्रुप में, रैपर ऑब्जेक्ट होते हैं. हालांकि, इससे कोई ऐसा साइकल नहीं बनता जिसे इकट्ठा नहीं किया जा सकता. ऐसा इसलिए है, क्योंकि GC उन ऑब्जेक्ट ग्रुप को रिलीज़ करने के लिए स्मार्ट है जिनके रैपर का अब रेफ़रंस नहीं दिया जाता. हालांकि, अगर किसी एक रैपर को रिलीज़ नहीं किया जाता है, तो पूरे ग्रुप और उससे जुड़े रैपर को होल्ड कर दिया जाएगा.