ऑब्जेक्ट पूल के साथ स्टैटिक मेमोरी JavaScript

शुरुआती जानकारी

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

आपकी 'यादें' टाइमलाइन का स्नैपशॉट

आपके किसी सहकर्मी का हंसने पर, जब उसे पता चलता है कि आपको याददाश्त से जुड़ी समस्या आ गई है.

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

आरी-टूथ का क्या मतलब है

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

कचरा इकट्ठा करने और परफ़ॉर्मेंस की लागत

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

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

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

अच्छी परफ़ॉर्मेंस वाले ऐप्लिकेशन, उपयोगकर्ताओं को बेहतरीन अनुभव देने के लिए, परफ़ॉर्मेंस के लिए एक जैसी सीमाएं तय करते हैं. कूड़ा इकट्ठा करने वाले सिस्टम इस लक्ष्य को शॉर्ट सर्किट कर सकते हैं, क्योंकि वे किसी भी समय कई बार चल सकते हैं और ऐप्लिकेशन को अपने परफ़ॉर्मेंस लक्ष्यों को पूरा करने के लिए ज़रूरी समय का फ़ायदा मिल सकता है.

मेमोरी चर्न आउट कम करें और कचरा हटाने पर लगने वाले टैक्स कम करें

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

यह प्रक्रिया आपके मेमोरी ग्राफ़ को इससे आगे ले जाएगी :

आपकी 'यादें' टाइमलाइन का स्नैपशॉट

को:

स्टैटिक मेमोरी JavaScript

इस मॉडल में, देखा जा सकता है कि ग्राफ़ में अब पैटर्न जैसा कोई हल्का नहीं है, लेकिन शुरुआत में बहुत ज़्यादा बढ़ता है और फिर समय के साथ धीरे-धीरे बढ़ता है. अगर मेमोरी चर्न की वजह से आपकी परफ़ॉर्मेंस से जुड़ी समस्याएं आ रही हैं, तो आप इस तरह का ग्राफ़ बनाना चाहेंगे.

स्टैटिक-मेमोरी JavaScript का इस्तेमाल करना

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

  1. अपने ऐप्लिकेशन को इस्तेमाल करें, ताकि यह पता लगाया जा सके कि अलग-अलग तरह के इस्तेमाल के लिए, ज़्यादा से ज़्यादा कितने (हर टाइप के) लाइव मेमोरी ऑब्जेक्ट की ज़रूरत है
  2. ज़्यादा से ज़्यादा रकम पहले से तय करने के लिए, अपने कोड को फिर से लागू करें. इसके बाद, मुख्य मेमोरी पर जाने के बजाय, उन्हें मैन्युअल तरीके से फ़ेच/रिलीज़ करें.

असल में, #1 हासिल करने के लिए हमें थोड़ा #2 करना होगा. इसलिए, चलिए शुरू करते हैं.

ऑब्जेक्ट पूल

आसान शब्दों में कहें, तो ऑब्जेक्ट पूलिंग, इस्तेमाल न किए गए ऐसे ऑब्जेक्ट के एक सेट को बनाए रखने की प्रोसेस है जिसमें कोई एक टाइप शेयर होता है. जब आपको अपने कोड के लिए किसी नए ऑब्जेक्ट की ज़रूरत होती है, तो सिस्टम मेमोरी हीप से कोई नया ऑब्जेक्ट असाइन करने के बजाय, आप पूल के किसी ऐसे ऑब्जेक्ट को रीसाइकल कर लेते हैं जिसका इस्तेमाल नहीं हुआ है. ऑब्जेक्ट के साथ बाहरी कोड पूरा हो जाने के बाद, उसे मुख्य मेमोरी पर रिलीज़ करने के बजाय, उसे पूल में वापस भेज दिया जाता है. ऑब्जेक्ट को कभी भी कोड से पहचान से नहीं हटाया जाता (यानी उसे मिटाया गया) नहीं, इसलिए ऑब्जेक्ट को इकट्ठा नहीं किया जाएगा. ऑब्जेक्ट पूल का इस्तेमाल करने से, प्रोग्रामर के पास मेमोरी को कंट्रोल करने की सुविधा वापस आ जाती है. इससे परफ़ॉर्मेंस पर, कूड़ा इकट्ठा करने वाले का असर कम हो जाता है.

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

var newEntity = gEntityObjectPool.allocate();
newEntity.pos = {x: 215, y: 88};

//..... do some stuff with the object that we need to do

gEntityObjectPool.free(newEntity); //free the object when we're done
newEntity = null; //free this object reference

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

पहले से तय किए गए ऑब्जेक्ट

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

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

function init() {
  //preallocate all our pools. 
  //Note that we keep each pool homogeneous wrt object types
  gEntityObjectPool.preAllocate(256);
  gDomObjectPool.preAllocate(888);
}

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

चांदी के बुलेट से बहुत दूर

ऐप्लिकेशन की ऐसी कैटगरी हैं जिनमें स्टैटिक मेमोरी ग्रोथ पैटर्न का इस्तेमाल किया जा सकता है. जैसा कि हमारे साथी Chrome DevRel Renato Mangini ने बताया है, हालांकि, इसकी कुछ कमियां हैं.

नतीजा

JavaScript को वेब के लिए सही होने की एक वजह इस बात पर निर्भर करती है कि इसे इस्तेमाल करना तेज़, मज़ेदार, और आसान है. ऐसा सिंटैक्स की पाबंदियों में कम रुकावट की वजह से होता है. साथ ही, इसकी वजह यह है कि आपकी तरफ़ से मेमोरी से जुड़ी समस्याओं को हल किया जाता है. आप कोड कर सकते हैं और गंदे काम को रहने दे सकते हैं. हालांकि, HTML5 गेम जैसे बेहतर परफ़ॉर्म करने वाले वेब ऐप्लिकेशन के लिए, GC अक्सर ज़रूरी फ़्रेम रेट के हिसाब से वीडियो का इस्तेमाल करना बंद कर देता है. इससे असली उपयोगकर्ता को कम अनुभव मिलता है. सावधानी से इस्तेमाल किए जाने वाले इंस्ट्रुमेंटेशन और ऑब्जेक्ट पूल का इस्तेमाल करके, फ़्रेम रेट पर इस बोझ को कम किया जा सकता है. साथ ही, इस समय को बेहतरीन बनाने के लिए फिर से इस्तेमाल किया जा सकता है.

स्रोत कोड

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

रेफ़रंस