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

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

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

इस पर जाएं:

इस मॉडल में, यह देखा जा सकता है कि ग्राफ़ में अब सॉटूथ जैसा पैटर्न नहीं है. इसके बजाय, शुरुआत में यह काफ़ी बढ़ता है और फिर समय के साथ धीरे-धीरे बढ़ता है. अगर आपको मेमोरी में बदलाव की वजह से परफ़ॉर्मेंस से जुड़ी समस्याएं आ रही हैं, तो आपको इस तरह का ग्राफ़ बनाना होगा.
स्टैटिक-मेमोरी JavaScript की ओर बढ़ना
स्टैटिक मेमोरी JavaScript एक ऐसी तकनीक है जिसमें आपके ऐप्लिकेशन के शुरू होने पर, उसकी लाइफ़टाइम के लिए ज़रूरी सभी मेमोरी को पहले से तय किया जाता है. साथ ही, ऑब्जेक्ट की ज़रूरत न होने पर, उसे प्रोसेस करने के दौरान उस मेमोरी को मैनेज किया जाता है. इस लक्ष्य को कुछ आसान चरणों में पूरा किया जा सकता है:
- अपने ऐप्लिकेशन को इंस्ट्रूमेंट करें, ताकि यह पता लगाया जा सके कि इस्तेमाल के अलग-अलग मामलों के लिए, हर टाइप के लाइव मेमोरी ऑब्जेक्ट की ज़्यादा से ज़्यादा संख्या क्या है
- ज़्यादा से ज़्यादा रकम को पहले से तय करने के लिए, अपना कोड फिर से लागू करें. इसके बाद, मुख्य मेमोरी में जाने के बजाय, उन्हें मैन्युअल तरीके से फ़ेच/रिलीज़ करें.
असल में, #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 के साथ काम करने वाले डेवलपर रेनाटो मैंगनी के मुताबिक, इसमें कुछ कमियां हैं.
नतीजा
JavaScript को वेब के लिए सबसे सही भाषा माना जाता है. इसकी एक वजह यह है कि इसे इस्तेमाल करना आसान है. साथ ही, इसमें काम करने में मज़ा आता है और यह तेज़ी से काम करती है. इसकी मुख्य वजह यह है कि इसमें सिंटैक्स से जुड़ी पाबंदियों को आसानी से समझा जा सकता है. साथ ही, यह आपकी ओर से मेमोरी से जुड़ी समस्याओं को मैनेज करता है. आपके पास कोड लिखने का विकल्प है और यह मशीन लर्निंग की मदद से, मुश्किल कामों को आसानी से कर सकती है. हालांकि, HTML5 गेम जैसे बेहतरीन परफ़ॉर्मेंस वाले वेब ऐप्लिकेशन के लिए, जीसी अक्सर ज़रूरी फ़्रेम रेट को कम कर सकता है. इससे, असली उपयोगकर्ता को खराब अनुभव मिलता है. कुछ सावधानी से इंस्ट्रूमेंटेशन और ऑब्जेक्ट पूल का इस्तेमाल करके, अपने फ़्रेम रेट पर इस बोझ को कम किया जा सकता है. साथ ही, उस समय का इस्तेमाल और शानदार चीज़ों के लिए किया जा सकता है.
सोर्स कोड
वेब पर ऑब्जेक्ट पूल के कई तरीके मौजूद हैं. इसलिए, हम आपको एक और तरीके के बारे में नहीं बताएंगे. इसके बजाय, हम आपको इन लेखों पर ले जाएंगे. इनमें से हर लेख में, लागू करने के बारे में खास जानकारी दी गई है. यह जानकारी इसलिए ज़रूरी है, क्योंकि हर ऐप्लिकेशन के इस्तेमाल के लिए, लागू करने की खास ज़रूरतें हो सकती हैं.
- Gamecore.js का ऑब्जेक्ट पूल
- Beej के ऑब्जेक्ट पूल
- Emehrkay का बहुत आसान ऑब्जेक्ट पूल
- स्टीफ़न लैंबर्ट का गेम पर फ़ोकस करने वाला ऑब्जेक्ट पूल
- RenderEngine का objectPool सेटअप