Unity गेम में एलएमके को ठीक करने के लिए, यह तरीका अपनाएं:

मेमोरी स्नैपशॉट पाना
Unity की ओर से मैनेज की गई मेमोरी का स्नैपशॉट पाने के लिए, Unity Profiler का इस्तेमाल करें. दूसरी इमेज में, मेमोरी मैनेजमेंट की उन लेयर को दिखाया गया है जिनका इस्तेमाल Unity, आपके गेम में मेमोरी को मैनेज करने के लिए करता है.

मैनेज की गई मेमोरी
Unity का मेमोरी मैनेजमेंट, कंट्रोल की गई मेमोरी लेयर लागू करता है. यह मैनेज किए गए हीप और गार्बेज कलेक्टर का इस्तेमाल करके, मेमोरी को अपने-आप असाइन और असाइन करता है. मैनेज की गई मेमोरी सिस्टम, C# स्क्रिप्टिंग एनवायरमेंट है. यह Mono या IL2CPP पर आधारित है. मैनेज की गई मेमोरी सिस्टम का फ़ायदा यह है कि यह मेमोरी के बंटवारे को अपने-आप खाली करने के लिए, गार्बेज कलेक्टर का इस्तेमाल करता है.
C# में अनमैनेज्ड मेमोरी
अनमैनेज्ड C# मेमोरी लेयर, नेटिव मेमोरी लेयर का ऐक्सेस देती है. इससे C# कोड का इस्तेमाल करते समय, मेमोरी के बंटवारे पर सटीक कंट्रोल मिलता है. मेमोरी मैनेजमेंट लेयर को Unity.Collections नेमस्पेस के ज़रिए ऐक्सेस किया जा सकता है. साथ ही, इसे UnsafeUtility.Malloc और UnsafeUtility.Free जैसे फ़ंक्शन के ज़रिए भी ऐक्सेस किया जा सकता है.
नेटिव मेमोरी
Unity का इंटरनल C/C++ कोर, सीन, ऐसेट, ग्राफ़िक्स एपीआई, ड्राइवर, सबसिस्टम, और प्लग-इन बफ़र को मैनेज करने के लिए, नेटिव मेमोरी सिस्टम का इस्तेमाल करता है. हालांकि, सीधे तौर पर ऐक्सेस करने की सुविधा सीमित है. फिर भी, Unity के C# API का इस्तेमाल करके, डेटा में सुरक्षित तरीके से बदलाव किया जा सकता है. साथ ही, नेटिव कोड का फ़ायदा पाया जा सकता है. नेटिव मेमोरी को सीधे तौर पर इंटरैक्ट करने की ज़रूरत बहुत कम पड़ती है. हालांकि, परफ़ॉइलर का इस्तेमाल करके, परफ़ॉर्मेंस पर नेटिव मेमोरी के असर को मॉनिटर किया जा सकता है. साथ ही, परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के लिए, सेटिंग में बदलाव किया जा सकता है.
C# और नेटिव कोड के बीच मेमोरी शेयर नहीं की जाती है. इसे इमेज 3 में दिखाया गया है. C# को जिस डेटा की ज़रूरत होती है उसे मैनेज की गई मेमोरी स्पेस में तब असाइन किया जाता है, जब उसकी ज़रूरत होती है.
मैनेज किए गए गेम के कोड (C#) को इंजन के नेटिव मेमोरी डेटा को ऐक्सेस करने के लिए, उदाहरण के लिए, GameObject.transform को कॉल करने पर, नेटिव कॉल किया जाता है. इससे नेटिव एरिया में मौजूद मेमोरी डेटा को ऐक्सेस किया जाता है. इसके बाद, Bindings का इस्तेमाल करके, C# को वैल्यू वापस भेजी जाती हैं. बाइंडिंग यह पक्का करती हैं कि हर प्लैटफ़ॉर्म के लिए, कॉलिंग के सही नियमों का पालन किया जाए. साथ ही, मैनेज किए गए टाइप को उनके नेटिव वर्शन में अपने-आप मार्शेल करने की प्रोसेस को मैनेज करती हैं.
ऐसा सिर्फ़ पहली बार होता है, क्योंकि transform प्रॉपर्टी को ऐक्सेस करने के लिए मैनेज किए गए शेल को नेटिव कोड में सेव किया जाता है. transform प्रॉपर्टी को कैश मेमोरी में सेव करने से, मैनेज किए गए और नेटिव कोड के बीच बार-बार होने वाले कॉल की संख्या कम हो सकती है. हालांकि, कैश मेमोरी में सेव करने की सुविधा कितनी काम की है, यह इस बात पर निर्भर करता है कि प्रॉपर्टी का इस्तेमाल कितनी बार किया जाता है. यह भी ध्यान दें कि इन एपीआई को ऐक्सेस करते समय, Unity नेटिव मेमोरी के कुछ हिस्सों को मैनेज की गई मेमोरी में कॉपी नहीं करता है.

ज़्यादा जानने के लिए, Unity में मेमोरी के बारे में जानकारी लेख पढ़ें.
इसके अलावा, मेमोरी बजट तय करना ज़रूरी है, ताकि आपका गेम बिना किसी रुकावट के चलता रहे. साथ ही, मेमोरी इस्तेमाल करने से जुड़े आंकड़ों या रिपोर्टिंग सिस्टम को लागू करने से यह पक्का किया जा सकता है कि हर नई रिलीज़, मेमोरी बजट से ज़्यादा न हो. Play Mode टेस्ट को कंटीन्यूअस इंटिग्रेशन (सीआई) के साथ इंटिग्रेट करके, गेम के कुछ हिस्सों में मेमोरी की खपत की पुष्टि की जा सकती है. यह बेहतर जानकारी पाने का एक और तरीका है.
ऐसेट मैनेज करना
मेमोरी की खपत का यह सबसे अहम और कार्रवाई करने लायक हिस्सा है. प्रोफ़ाइल को जल्द से जल्द अपडेट करें.
Android गेम में मेमोरी का इस्तेमाल, गेम के टाइप, ऐसेट की संख्या और टाइप, और मेमोरी ऑप्टिमाइज़ेशन की रणनीतियों के आधार पर अलग-अलग हो सकता है. हालांकि, मेमोरी के इस्तेमाल में योगदान देने वाले सामान्य कॉम्पोनेंट में आम तौर पर टेक्सचर, मेश, ऑडियो फ़ाइलें, शेडर, ऐनिमेशन, और स्क्रिप्ट शामिल होती हैं.
डुप्लीकेट ऐसेट का पता लगाना
पहला चरण, मेमोरी प्रोफ़ाइलर, बिल्ड रिपोर्ट टूल या प्रोजेक्ट ऑडिटर का इस्तेमाल करके, खराब तरीके से कॉन्फ़िगर की गई ऐसेट और डुप्लीकेट ऐसेट का पता लगाना है.
टेक्स्चर
अपने गेम के लिए, डिवाइस के साथ काम करने वाले फ़ॉर्मैट का विश्लेषण करें. इसके बाद, सही टेक्सचर फ़ॉर्मैट तय करें. Play ऐसेट डिलीवरी, Addressable या AssetBundle के साथ ज़्यादा मैन्युअल प्रोसेस का इस्तेमाल करके, हाई-एंड और लो-एंड डिवाइसों के लिए टेक्सचर बंडल को अलग-अलग किया जा सकता है.
अपने मोबाइल गेम की परफ़ॉर्मेंस ऑप्टिमाइज़ करें और Unity में टेक्सचर इंपोर्ट करने की सेटिंग ऑप्टिमाइज़ करना चर्चा पोस्ट में उपलब्ध सबसे लोकप्रिय सुझावों का पालन करें. इसके बाद, समस्या हल करने के लिए ये तरीके आज़माएं:
कम मेमोरी इस्तेमाल करने के लिए, एएसटीसी फ़ॉर्मैट का इस्तेमाल करके टेक्सचर को कंप्रेस करें. साथ ही, ज़्यादा ब्लॉक रेट, जैसे कि 8x8 का इस्तेमाल करके एक्सपेरिमेंट करें.
अगर ETC2 का इस्तेमाल करना ज़रूरी है, तो अपनी टेक्सचर को एटलस में पैक करें. एक टेक्सचर में कई टेक्सचर रखने से, यह पक्का होता है कि उसका डाइमेंशन 2 की पावर में हो. इससे ड्रॉ कॉल कम हो सकते हैं और रेंडरिंग की स्पीड बढ़ सकती है.
RenderTarget टेक्सचर फ़ॉर्मैट और साइज़ को ऑप्टिमाइज़ करें. ज़रूरत से ज़्यादा हाई रिज़ॉल्यूशन वाले टेक्सचर का इस्तेमाल न करें. मोबाइल डिवाइसों पर छोटी बनावट वाली इमेज का इस्तेमाल करने से मेमोरी बचती है.
टेक्स्चर के लिए मेमोरी को सेव करने के लिए, टेक्स्चर चैनल पैकिंग का इस्तेमाल करें.
मेश और मॉडल
सबसे पहले, बुनियादी सेटिंग (पेज 27) देखें. इसके बाद, मेश इंपोर्ट करने की इन सेटिंग की पुष्टि करें:
- ज़रूरत से ज़्यादा और छोटे मेश मर्ज करें.
- सीन में मौजूद ऑब्जेक्ट के लिए वर्टेक्स की संख्या कम करें. उदाहरण के लिए, स्टैटिक या दूर के ऑब्जेक्ट.
- ज़्यादा जानकारी वाली ऐसेट के लिए, लेवल ऑफ़ डिटेल (एलओडी) ग्रुप जनरेट करें.
मटेरियल और शेडर
- बिल्ड प्रोसेस के दौरान, इस्तेमाल न किए गए शेडर वैरिएंट को प्रोग्राम के हिसाब से हटा दें.
- अक्सर इस्तेमाल किए जाने वाले शेडर वैरिएंट को यूबर शेडर में शामिल करें, ताकि शेडर डुप्लीकेट न हों.
- डाइनैमिक शेडर लोडिंग की सुविधा चालू करें, ताकि VRAM/RAM में पहले से लोड किए गए शेडर की वजह से मेमोरी का ज़्यादा इस्तेमाल होने की समस्या को ठीक किया जा सके. हालांकि, अगर शेडर कंपाइलेशन की वजह से फ़्रेम में रुकावट आ रही है, तो इस पर ध्यान दें.
- सभी वैरिएंट लोड होने से रोकने के लिए, डाइनैमिक शेडर लोडिंग का इस्तेमाल करें. ज़्यादा जानकारी के लिए, शेडर बनाने में लगने वाले समय और मेमोरी के इस्तेमाल में सुधार ब्लॉग पोस्ट पढ़ें.
MaterialPropertyBlocks
का इस्तेमाल करके, मटीरियल इंस्टेंसिंग का सही तरीके से इस्तेमाल करें.
ऑडियो
सबसे पहले, बुनियादी सेटिंग (पेज 41) देखें. इसके बाद, मेश इंपोर्ट करने की इन सेटिंग की पुष्टि करें:
- FMOD या Wwise जैसे तीसरे पक्ष के ऑडियो इंजन का इस्तेमाल करते समय, इस्तेमाल नहीं किए गए या ज़रूरत से ज़्यादा
AudioClip
रेफ़रंस हटाएं. - ऑडियो डेटा को पहले से लोड करना. उन क्लिप के लिए प्रीलोडिंग की सुविधा बंद करें जिनकी ज़रूरत रनटाइम या सीन के शुरू होने के दौरान तुरंत नहीं होती है. इससे सीन शुरू होने के दौरान, मेमोरी ओवरहेड को कम करने में मदद मिलती है.
ऐनिमेशन
- कीफ़्रेम की संख्या कम करने और गैर-ज़रूरी डेटा हटाने के लिए, Unity की ऐनिमेशन कंप्रेस करने की सेटिंग में बदलाव करें.
- मुख्य फ़्रेम कम करना: यह सुविधा, गैर-ज़रूरी मुख्य फ़्रेम को अपने-आप हटा देती है
- क्वाटर्नियन कंप्रेस करने की सुविधा: इससे रोटेशन डेटा को कंप्रेस किया जाता है, ताकि मेमोरी का इस्तेमाल कम हो
रिग या ऐनिमेशन टैब में जाकर, ऐनिमेशन इंपोर्ट करने की सेटिंग में कंप्रेशन की सेटिंग अडजस्ट की जा सकती हैं.
अलग-अलग ऑब्जेक्ट के लिए, ऐनिमेशन क्लिप को डुप्लीकेट करने के बजाय, उनका फिर से इस्तेमाल करें.
ऐनिमेटर ओवरराइड कंट्रोलर का इस्तेमाल करके, ऐनिमेटर कंट्रोलर का फिर से इस्तेमाल करें. साथ ही, अलग-अलग वर्णों के लिए खास क्लिप बदलें.
फ़िज़िक्स पर आधारित ऐनिमेशन बेक करें: अगर आपके ऐनिमेशन फ़िज़िक्स पर आधारित हैं या प्रोसीजरल हैं, तो उन्हें ऐनिमेशन क्लिप में बेक करें, ताकि रनटाइम कैलकुलेशन से बचा जा सके.
स्केलेटन रिग को ऑप्टिमाइज़ करें: रिग में कम हड्डियों का इस्तेमाल करें, ताकि जटिलता और मेमोरी की खपत कम हो.
- छोटे या स्थिर ऑब्जेक्ट के लिए, बहुत ज़्यादा हड्डियों का इस्तेमाल न करें.
- अगर कुछ हड्डियों को ऐनिमेट नहीं किया गया है या उनकी ज़रूरत नहीं है, तो उन्हें रिग से हटा दें.
ऐनिमेशन क्लिप की अवधि कम करें.
- ऐनिमेशन क्लिप को ट्रिम करें, ताकि सिर्फ़ ज़रूरी फ़्रेम शामिल किए जा सकें. ऐसे ऐनिमेशन सेव न करें जिनका इस्तेमाल नहीं किया गया है या जो बहुत लंबे हैं.
- बार-बार होने वाली गतिविधियों के लिए, लंबी क्लिप बनाने के बजाय लूप में चलने वाले ऐनिमेशन का इस्तेमाल करें.
पक्का करें कि सिर्फ़ एक ऐनिमेशन कॉम्पोनेंट अटैच किया गया हो या चालू किया गया हो. उदाहरण के लिए, अगर ऐनिमेटर का इस्तेमाल किया जा रहा है, तो लेगसी ऐनिमेशन कॉम्पोनेंट को बंद करें या हटाएं.
अगर ज़रूरत न हो, तो ऐनिमेटर का इस्तेमाल न करें. सामान्य वीएफ़एक्स के लिए, ट्विनिंग लाइब्रेरी का इस्तेमाल करें या स्क्रिप्ट में विज़ुअल इफ़ेक्ट लागू करें. ऐनिमेशन सिस्टम में ज़्यादा रिसॉर्स लग सकते हैं. खास तौर पर, कम सुविधाओं वाले मोबाइल डिवाइसों में.
ज़्यादा ऐनिमेशन मैनेज करते समय, ऐनिमेशन के लिए जॉब सिस्टम का इस्तेमाल करें. इस सिस्टम को पूरी तरह से फिर से डिज़ाइन किया गया है, ताकि यह मेमोरी का कम इस्तेमाल करे.
सीन
नए सीन लोड होने पर, वे ऐसेट को डिपेंडेंसी के तौर पर इस्तेमाल करते हैं. हालांकि, ऐसेट के लाइफ़साइकल को मैनेज करने की सुविधा के बिना, इन डिपेंडेंसी को रेफ़रंस काउंटर से मॉनिटर नहीं किया जाता. इस वजह से, इस्तेमाल न किए गए सीन को अनलोड करने के बाद भी ऐसेट मेमोरी में बनी रह सकती हैं. इससे मेमोरी फ़्रैगमेंटेशन हो सकता है.
- बार-बार इस्तेमाल होने वाले गेमप्ले एलिमेंट के लिए, Unity की ऑब्जेक्ट पूलिंग का इस्तेमाल करें. ऐसा इसलिए, क्योंकि ऑब्जेक्ट पूलिंग, फिर से इस्तेमाल करने के लिए ऑब्जेक्ट इंस्टेंस के कलेक्शन को होल्ड करने के लिए स्टैक का इस्तेमाल करती है. साथ ही, यह थ्रेड सेफ़ नहीं है.
Instantiate
औरDestroy
को कम करने से, सीपीयू की परफ़ॉर्मेंस और मेमोरी की स्थिरता, दोनों बेहतर होती हैं. - ऐसेट अनलोड की जा रही हैं:
- स्प्लैश स्क्रीन या लोडिंग स्क्रीन जैसे कम ज़रूरी समय के दौरान, ऐसेट को रणनीतिक तरीके से अनलोड करें.
Resources.UnloadUnusedAssets
का बार-बार इस्तेमाल करने से, सीपीयू प्रोसेसिंग में अचानक बढ़ोतरी होती है. ऐसा इसलिए होता है, क्योंकि अंदरूनी तौर पर निर्भरता को मॉनिटर करने की कार्रवाइयां ज़्यादा होती हैं.- GC.MarkDependencies प्रोफ़ाइल मार्कर में, सीपीयू के इस्तेमाल में हुए बड़े उतार-चढ़ाव की जांच करें.
इसके एक्ज़ीक्यूशन की फ़्रीक्वेंसी को कम करें या इसे हटा दें. साथ ही, Resources.UnloadAsset का इस्तेमाल करके, कुछ संसाधनों को मैन्युअल तरीके से अनलोड करें. इसके बजाय,
Resources.UnloadUnusedAssets()
पर भरोसा न करें.
- Resources.UnloadUnusedAssets का लगातार इस्तेमाल करने के बजाय, सीन को फिर से व्यवस्थित करें.
Addressables
के लिएResources.UnloadUnusedAssets()
को कॉल करने से, डाइनैमिक रूप से लोड किए गए बंडल अनजाने में अनलोड हो सकते हैं. डाइनैमिक तरीके से लोड की गई ऐसेट की लाइफ़साइकल को ध्यान से मैनेज करें.
अन्य चीज़ें
सीन ट्रांज़िशन की वजह से फ़्रैगमेंटेशन — जब
Resources.UnloadUnusedAssets()
तरीके को कॉल किया जाता है, तो Unity ये काम करता है:- उन ऐसेट के लिए मेमोरी खाली करता है जिनका अब इस्तेमाल नहीं किया जा रहा है
- यह फ़ंक्शन, गार्बेज कलेक्टर की तरह काम करता है. यह मैनेज किए गए और नेटिव ऑब्जेक्ट हीप की जांच करता है, ताकि इस्तेमाल न की गई ऐसेट का पता लगाया जा सके. इसके बाद, यह उन्हें अनलोड कर देता है
- यह फ़ंक्शन, टेक्सचर, मेश, और ऐसेट की मेमोरी को साफ़ करता है. हालांकि, इसके लिए यह ज़रूरी है कि कोई ऐक्टिव रेफ़रंस मौजूद न हो
AssetBundle
याAddressable
- इस क्षेत्र में बदलाव करना मुश्किल है. साथ ही, रणनीतियों को लागू करने के लिए टीम को मिलकर काम करना पड़ता है. हालांकि, इन रणनीतियों को अपनाने के बाद, मेमोरी का इस्तेमाल काफ़ी कम हो जाता है, डाउनलोड का साइज़ कम हो जाता है, और क्लाउड की लागत कम हो जाती है. Unity में ऐसेट मैनेजमेंट के बारे में ज़्यादा जानकारी के लिए,Addressables
देखें.शेयर की गई डिपेंडेंसी को एक जगह पर मैनेज करना &mdash: शेयर की गई डिपेंडेंसी, जैसे कि शेडर, टेक्सचर, और फ़ॉन्ट को व्यवस्थित तरीके से अलग-अलग बंडल या
Addressable
ग्रुप में रखें. इससे डुप्लीकेट ऐसेट कम हो जाती हैं. साथ ही, यह पक्का किया जाता है कि गैर-ज़रूरी ऐसेट को असरदार तरीके से अनलोड किया जाए.डिपेंडेंसी को ट्रैक करने के लिए,
Addressables
का इस्तेमाल करें - Addressables लोड करने और अनलोड करने की प्रोसेस को आसान बनाते हैं. साथ ही, उन डिपेंडेंसी को अपने-आप अनलोड कर सकते हैं जिनका अब कोई रेफ़रंस नहीं है. कॉन्टेंट मैनेजमेंट और डिपेंडेंसी रिज़ॉल्यूशन के लिए,Addressables
पर स्विच करना एक अच्छा विकल्प हो सकता है. हालांकि, यह गेम के हिसाब से तय होगा. ज़रूरत से ज़्यादा डुप्लीकेट या डिपेंडेंसी का पता लगाने के लिए, Analyze टूल की मदद से डिपेंडेंसी चेन का विश्लेषण करें. इसके अलावा, अगर AssetBundles का इस्तेमाल किया जा रहा है, तो Unity Data Tools देखें.TypeTrees
- अगर आपके गेम केAddressables
औरAssetBundles
को प्लेयर के Unity के वर्शन का इस्तेमाल करके बनाया और डिप्लॉय किया गया है और उन्हें प्लेयर के अन्य बिल्ड के साथ काम करने की ज़रूरत नहीं है, तोTypeTree
को लिखने की सुविधा बंद करें. इससे बंडल का साइज़ कम हो जाएगा और सीरियलाइज़ की गई फ़ाइल ऑब्जेक्ट मेमोरी फ़ुटप्रिंट कम हो जाएगा. DisableWriteTypeTree को सेट करने के लिए, स्थानीय Addressables पैकेज की सेटिंग ContentBuildFlags में जाकर, बिल्ड प्रोसेस में बदलाव करें.
गारबेज कलेक्टर के साथ काम करने वाला कोड लिखना
Unity, मेमोरी को मैनेज करने के लिए गार्बेज कलेक्शन (GC) का इस्तेमाल करता है. यह सुविधा, इस्तेमाल न की गई मेमोरी की पहचान करके उसे अपने-आप खाली कर देती है. GC ज़रूरी है. हालांकि, इसे सही तरीके से मैनेज न करने पर, परफ़ॉर्मेंस से जुड़ी समस्याएं हो सकती हैं. जैसे, फ़्रेम रेट में अचानक बढ़ोतरी. ऐसा इसलिए होता है, क्योंकि इस प्रोसेस के दौरान गेम कुछ समय के लिए रुक सकता है. इससे परफ़ॉर्मेंस में रुकावटें आती हैं और उपयोगकर्ता को खराब अनुभव मिलता है.
मैनेज किए गए हीप के लिए मेमोरी के बार-बार होने वाले असाइनमेंट को कम करने की उपयोगी तकनीकों के बारे में जानने के लिए, Unity मैनुअल पढ़ें. उदाहरणों के लिए, UnityPerformanceTuningBible के पेज 271 पर जाएं.
गार्बेज कलेक्टर के लिए मेमोरी का कम से कम हिस्सा असाइन करें:
- LINQ, लैम्डा, और क्लोज़र का इस्तेमाल न करें. ये हीप मेमोरी को असाइन करते हैं.
- स्ट्रिंग कॉनकैटेनेशन के बजाय, बदलने वाली स्ट्रिंग के लिए
StringBuilder
का इस्तेमाल करें. - कलेक्शन को फिर से इंस्टैंशिएट करने के बजाय,
COLLECTIONS.Clear()
को कॉल करके उनका फिर से इस्तेमाल करें.
ज़्यादा जानकारी के लिए, Unity गेम की प्रोफ़ाइलिंग के बारे में पूरी जानकारी देने वाली गाइड ई-बुक पढ़ें.
यूज़र इंटरफ़ेस (यूआई) कैनवस के अपडेट मैनेज करें:
- यूज़र इंटरफ़ेस (यूआई) एलिमेंट में डाइनैमिक बदलाव — जब टेक्स्ट, इमेज या
RectTransform
जैसी प्रॉपर्टी वाले यूज़र इंटरफ़ेस (यूआई) एलिमेंट अपडेट किए जाते हैं, तो इंजन कुछ समय के लिए ऑब्जेक्ट के लिए मेमोरी असाइन कर सकता है. उदाहरण के लिए, टेक्स्ट कॉन्टेंट बदलना, एलिमेंट का साइज़ बदलना या पोज़िशन में ऐनिमेशन जोड़ना. - स्ट्रिंग असाइनमेंट — टेक्स्ट जैसे यूज़र इंटरफ़ेस (यूआई) एलिमेंट के लिए, अक्सर स्ट्रिंग अपडेट करने की ज़रूरत होती है. ऐसा इसलिए, क्योंकि ज़्यादातर प्रोग्रामिंग भाषाओं में स्ट्रिंग में बदलाव नहीं किया जा सकता.
- डर्टी कैनवस — जब कैनवस पर कुछ बदलता है, तो पूरे कैनवस या उसके किसी हिस्से को डर्टी के तौर पर मार्क किया जा सकता है और उसे फिर से बनाया जा सकता है. जैसे, साइज़ बदलना, एलिमेंट चालू और बंद करना या लेआउट प्रॉपर्टी में बदलाव करना. इससे कुछ समय के लिए डेटा स्ट्रक्चर (जैसे, मेश डेटा, वर्टेक्स बफ़र या लेआउट कैलकुलेशन) बन सकते हैं. इससे गार्बेज जनरेट होता है.
- जटिल या बार-बार होने वाले अपडेट — अगर कैनवस में बहुत सारे एलिमेंट हैं या उसे बार-बार अपडेट किया जाता है (उदाहरण के लिए, हर फ़्रेम), तो इन रीबिल्ड की वजह से मेमोरी का इस्तेमाल काफ़ी बढ़ सकता है.
- यूज़र इंटरफ़ेस (यूआई) एलिमेंट में डाइनैमिक बदलाव — जब टेक्स्ट, इमेज या
इंक्रीमेंटल जीसी चालू करें, ताकि कई फ़्रेम में मेमोरी को खाली करके, बड़े कलेक्शन के स्पाइक को कम किया जा सके. प्रोफ़ाइल करें, ताकि यह पुष्टि की जा सके कि इस विकल्प से आपके गेम की परफ़ॉर्मेंस और मेमोरी फ़ुटप्रिंट बेहतर होता है या नहीं.
अगर आपके गेम में मेमोरी को मैनेज करने के लिए, कंट्रोल किए गए तरीके की ज़रूरत है, तो गारबेज कलेक्शन मोड को मैन्युअल पर सेट करें. इसके बाद, लेवल बदलने पर या गेमप्ले के चालू न होने पर, कचरा इकट्ठा करने की सुविधा को कॉल करें.
गेम की स्थिति में बदलाव होने पर, मैन्युअल गार्बेज कलेक्शन GC.Collect() कॉल शुरू करें. उदाहरण के लिए, लेवल स्विच करना.
कोड लिखने के सामान्य तरीकों से शुरू करके, ऐरे को ऑप्टिमाइज़ करें. अगर ज़रूरी हो, तो बड़ी ऐरे के लिए नेटिव ऐरे या अन्य नेटिव कंटेनर का इस्तेमाल करें.
मैनेज किए जा रहे ऑब्जेक्ट की निगरानी करने के लिए, Unity Memory Profiler जैसे टूल का इस्तेमाल करें. इससे डिस्ट्रक्शन के बाद भी बने रहने वाले अनमैनेज्ड ऑब्जेक्ट रेफ़रंस को ट्रैक किया जा सकता है.
ऑटोमेटेड अप्रोच के लिए, परफ़ॉर्मेंस रिपोर्टिंग टूल को सबमिट करने के लिए, प्रोफ़ाइलर मार्कर का इस्तेमाल करें.
मेमोरी लीक और फ़्रैगमेंटेशन से बचना
मेमोरी लीक
C# कोड में, जब किसी Unity ऑब्जेक्ट का रेफ़रंस ऑब्जेक्ट के डिस्ट्रॉय होने के बाद मौजूद होता है, तो मैनेज किया गया रैपर ऑब्जेक्ट, जिसे ManagedShell कहा जाता है, मेमोरी में बना रहता है. जब सीन को अनलोड किया जाता है या जब मेमोरी से जुड़ा GameObject या उसके किसी पैरंट ऑब्जेक्ट को Destroy()
तरीके से डिस्ट्रॉय किया जाता है, तब रेफ़रंस से जुड़ी नेटिव मेमोरी रिलीज़ हो जाती है. हालांकि, अगर Scene या GameObject के अन्य रेफ़रंस नहीं हटाए गए हैं, तो मैनेज की गई मेमोरी लीक हुए शेल ऑब्जेक्ट के तौर पर बनी रह सकती है. मैनेज किए गए शेल ऑब्जेक्ट के बारे में ज़्यादा जानने के लिए, मैनेज किए गए शेल ऑब्जेक्ट का मैन्युअल देखें.
इसके अलावा, इवेंट की सदस्यताएं, लैम्डा और क्लोज़र, स्ट्रिंग कॉनकैटेनेशन, और पूल किए गए ऑब्जेक्ट को सही तरीके से मैनेज न करने की वजह से मेमोरी लीक हो सकती है:
- शुरू करने के लिए, मेमोरी लीक ढूंढना लेख पढ़ें, ताकि Unity के मेमोरी स्नैपशॉट की तुलना सही तरीके से की जा सके.
- इवेंट की सदस्यताएं और मेमोरी लीक की जांच करें. अगर ऑब्जेक्ट, इवेंट की सदस्यता लेते हैं (उदाहरण के लिए, डेलिगेट या UnityEvents के ज़रिए), लेकिन डिस्ट्रॉय होने से पहले सदस्यता नहीं छोड़ते हैं, तो इवेंट मैनेजर या पब्लिशर उन ऑब्जेक्ट के रेफ़रंस सेव कर सकता है. इससे उन ऑब्जेक्ट को गार्बेज कलेक्शन से रोका जाता है. इससे मेमोरी लीक होती है.
- उन ग्लोबल या सिंगलटन क्लास इवेंट को मॉनिटर करें जिनका ऑब्जेक्ट डिस्ट्रक्शन पर रजिस्ट्रेशन रद्द नहीं किया गया है. उदाहरण के लिए, ऑब्जेक्ट डिस्ट्रक्टर में डेलिगेट की सदस्यता छोड़ना या उन्हें अनहुक करना.
- पक्का करें कि पूल किए गए ऑब्जेक्ट को डिस्ट्रॉय करने से, टेक्स्ट मेश कॉम्पोनेंट, टेक्सचर, और पैरंट गेमऑब्जेक्ट के रेफ़रंस पूरी तरह से हट जाएं.
- ध्यान रखें कि Unity Memory Profiler के स्नैपशॉट की तुलना करते समय, अगर आपको मेमोरी इस्तेमाल करने में अंतर दिखता है और इसकी वजह साफ़ तौर पर नहीं बताई गई है, तो हो सकता है कि यह अंतर ग्राफ़िक्स ड्राइवर या ऑपरेटिंग सिस्टम की वजह से हो.
मेमोरी फ़्रैगमेंटेशन
मेमोरी फ़्रैगमेंटेशन तब होता है, जब कई छोटे-छोटे हिस्सों को किसी भी क्रम में खाली कर दिया जाता है. ढेर में मेमोरी को क्रम से बांटा जाता है. इसका मतलब है कि जब पिछले हिस्से में जगह खत्म हो जाती है, तब मेमोरी के नए हिस्से बनाए जाते हैं. इसलिए, नए ऑब्जेक्ट पुराने चंक की खाली जगहों को नहीं भरते हैं. इससे फ़्रैगमेंटेशन होता है. इसके अलावा, कुछ समय के लिए बहुत ज़्यादा मेमोरी असाइन करने से, गेम के सेशन के दौरान मेमोरी का फ़्रैगमेंटेशन हो सकता है.
यह समस्या तब ज़्यादा होती है, जब कम समय के लिए बड़े पैमाने पर किए गए मेमोरी असाइनमेंट, लंबे समय के लिए किए गए मेमोरी असाइनमेंट के आस-पास किए जाते हैं.
लाइफ़स्पैन के आधार पर ग्रुप असाइनमेंट; सबसे सही तरीका यह है कि लंबे समय तक चलने वाले असाइनमेंट को ऐप्लिकेशन के लाइफ़साइकल की शुरुआत में एक साथ किया जाए.
ऑब्ज़र्वर और इवेंट मैनेजर
- (मेमोरी लीक)77 सेक्शन में बताई गई समस्या के अलावा, समय के साथ मेमोरी लीक से फ़्रैगमेंटेशन हो सकता है. ऐसा इसलिए होता है, क्योंकि यह उन ऑब्जेक्ट को आवंटित की गई मेमोरी को छोड़ देता है जिनका अब इस्तेमाल नहीं किया जा रहा है.
- पक्का करें कि पूल किए गए ऑब्जेक्ट को डिस्ट्रॉय करने से, टेक्स्ट मेश कॉम्पोनेंट, टेक्सचर, और पैरंट
GameObjects
के रेफ़रंस पूरी तरह से हट जाएं. - इवेंट मैनेजर, इवेंट की सदस्यताएं मैनेज करने के लिए अक्सर सूचियां या शब्दकोश बनाते और सेव करते हैं. अगर रनटाइम के दौरान इनकी संख्या में लगातार बदलाव होता रहता है, तो बार-बार मेमोरी के बंटवारे और उसे खाली करने की वजह से, मेमोरी फ़्रैगमेंटेशन हो सकता है.
कोड
- को-रूटीन कभी-कभी मेमोरी असाइन करते हैं. इससे आसानी से बचा जा सकता है. इसके लिए, हर बार नया IEnumerator घोषित करने के बजाय, IEnumerator के रिटर्न स्टेटमेंट को कैश मेमोरी में सेव करें.
- पूल किए गए ऑब्जेक्ट की लाइफ़साइकल की स्थितियों पर लगातार नज़र रखें, ताकि
UnityEngine.Object
घोस्ट रेफ़रंस न बने रहें.
ऐसेट
- टेक्स्ट पर आधारित गेम के अनुभवों के लिए, डाइनैमिक फ़ॉलबैक सिस्टम का इस्तेमाल करें. इससे, एक से ज़्यादा भाषाओं के लिए सभी फ़ॉन्ट को पहले से लोड करने से बचा जा सकता है.
- ऐसेट (जैसे, टेक्सचर और पार्टिकल) को टाइप और अनुमानित लाइफ़साइकल के हिसाब से एक साथ व्यवस्थित करें.
- ऐसेट को छोटा करें. इसके लिए, आइडल लाइफ़साइकल एट्रिब्यूट का इस्तेमाल करें. जैसे, ग़ैर-ज़रूरी यूज़र इंटरफ़ेस (यूआई) इमेज और स्टैटिक मेश.
लाइफ़टाइम के आधार पर किए गए असाइनमेंट
- ऐप्लिकेशन के लाइफ़साइकल की शुरुआत में, लंबे समय तक इस्तेमाल होने वाली ऐसेट असाइन करें. इससे यह पक्का किया जा सकेगा कि उन्हें कम जगह में असाइन किया गया है.
- मेमोरी का ज़्यादा इस्तेमाल करने वाले या कुछ समय के लिए मौजूद रहने वाले डेटा स्ट्रक्चर (उदाहरण के लिए, फ़िज़िक्स क्लस्टर) के लिए, NativeCollections या कस्टम ऐलोकेटर का इस्तेमाल करें.
कोड से जुड़ी और एक्ज़ीक्यूटेबल मेमोरी ऐक्शन
गेम के एक्ज़ीक्यूटेबल और प्लगिन भी मेमोरी के इस्तेमाल पर असर डालते हैं.
IL2CPP मेटाडेटा
IL2CPP, हर टाइप (जैसे कि क्लास, जेनेरिक, और डेलिगेट) के लिए मेटाडेटा जनरेट करता है. यह मेटाडेटा, बिल्ड टाइम पर जनरेट होता है. इसके बाद, इसका इस्तेमाल रिफ़्लेक्शन, टाइप चेकिंग, और रनटाइम से जुड़ी अन्य कार्रवाइयों के लिए किया जाता है. यह मेटाडेटा मेमोरी में सेव होता है. साथ ही, यह ऐप्लिकेशन की कुल मेमोरी फ़ुटप्रिंट में काफ़ी योगदान दे सकता है. IL2CPP की मेटाडेटा कैश मेमोरी, शुरू होने और लोड होने के समय को कम करने में अहम भूमिका निभाती है. इसके अलावा, IL2CPP कुछ मेटाडेटा एलिमेंट (उदाहरण के लिए, सामान्य टाइप या क्रम से लगाई गई जानकारी) को डुप्लीकेट नहीं करता है. इससे मेमोरी का इस्तेमाल बढ़ सकता है. प्रोजेक्ट में एक ही तरह के टाइप का बार-बार इस्तेमाल करने से, यह समस्या और बढ़ जाती है.
IL2CPP मेटाडेटा को इन तरीकों से कम किया जा सकता है:
- रिफ़्लेक्शन एपीआई का इस्तेमाल न करें, क्योंकि ये IL2CPP मेटाडेटा के लिए मेमोरी तय करने में अहम भूमिका निभाते हैं
- पहले से मौजूद पैकेज बंद करना
- Unity 2022 में पूरी तरह से सामान्य शेयरिंग की सुविधा लागू की गई है. इससे सामान्य शेयरिंग की वजह से होने वाले ओवरहेड को कम करने में मदद मिलेगी. हालांकि, ऐलोकेशन को और कम करने के लिए, जेनेरिक का इस्तेमाल कम करें.
कोड स्ट्रिपिंग
कोड स्ट्रिपिंग की मदद से, न सिर्फ़ बिल्ड का साइज़ कम किया जा सकता है, बल्कि मेमोरी का इस्तेमाल भी कम किया जा सकता है. IL2CPP स्क्रिप्टिंग बैकएंड के ख़िलाफ़ बिल्ड करते समय, मैनेज किए गए बाइटकोड स्ट्रिपिंग (जो डिफ़ॉल्ट रूप से चालू होती है) की सुविधा, मैनेज की गई असेंबलियों से इस्तेमाल न होने वाले कोड को हटा देती है. यह प्रोसेस, रूट असेंबली तय करके काम करती है. इसके बाद, स्टैटिक कोड विश्लेषण का इस्तेमाल करके यह पता लगाया जाता है कि रूट असेंबली, मैनेज किए गए अन्य कोड का इस्तेमाल कैसे करती हैं. ऐसे कोड को हटा दिया जाता है जिस तक पहुंचा नहीं जा सकता. मैनेज किए गए कोड को हटाने की सुविधा के बारे में ज़्यादा जानने के लिए, ऑप्टिमाइज़ेशन के बारे में जानकारी देने वाला ब्लॉग: Unity 2020 LTS की मदद से, मैनेज किए गए कोड को बेहतर तरीके से हटाना और मैनेज किए गए कोड को हटाने की सुविधा से जुड़ा दस्तावेज़ पढ़ें.
नेटिव ऐलोकेटर
मेमोरी ऐलोकेटर को बेहतर बनाने के लिए, नेटिव मेमोरी ऐलोकेटर आज़माएं. अगर गेम में मेमोरी कम है, तो छोटे मेमोरी ब्लॉक का इस्तेमाल करें. भले ही, इसमें धीमी गति से मेमोरी असाइन करने वाले फ़ंक्शन का इस्तेमाल करना पड़े. ज़्यादा जानने के लिए, डाइनैमिक हीप ऐलोकेटर का उदाहरण देखें.
नेटिव प्लगिन और एसडीके मैनेज करना
समस्या पैदा करने वाला प्लगिन ढूंढें — हर प्लगिन को हटाएं और गेम की मेमोरी के स्नैपशॉट की तुलना करें. इसमें Scripting Define Symbols की मदद से, कोड की कई सुविधाओं को बंद करना और इंटरफ़ेस की मदद से, एक-दूसरे से जुड़ी क्लास को फिर से व्यवस्थित करना शामिल है. गेम प्रोग्रामिंग पैटर्न की मदद से, अपने कोड को बेहतर बनाएं लेख पढ़ें. इससे आपको बाहरी डिपेंडेंसी को बंद करने में मदद मिलेगी. साथ ही, यह भी पक्का किया जा सकेगा कि आपका गेम खेलने लायक बना रहे.
प्लगिन या एसडीके के लेखक से संपर्क करें — ज़्यादातर प्लगिन ओपन सोर्स नहीं होते हैं.
प्लगिन के मेमोरी इस्तेमाल करने की प्रोसेस को दोहराएं — मेमोरी असाइन करने वाला एक आसान प्लगिन लिखें. इसके लिए, इस Unity प्लगिन को रेफ़रंस के तौर पर इस्तेमाल करें. Android Studio का इस्तेमाल करके, मेमोरी स्नैपशॉट की जांच करें. ऐसा इसलिए, क्योंकि Unity इन मेमोरी स्नैपशॉट को ट्रैक नहीं करता. इसके अलावा, एक ही प्रोजेक्ट में
MemoryInfo
क्लास औरRuntime.totalMemory()
तरीके को कॉल करें.
Unity प्लगिन, Java और नेटिव मेमोरी असाइन करता है. इसे इस तरह से किया जा सकता है:
Java
byte[] largeObject = new byte[1024 * 1024 * megaBytes];
list.add(largeObject);
नेटिव
char* buffer = new char[megabytes * 1024 * 1024];
// Random data to fill the buffer
for (int i = 1; i < megabytes * 1024 * 1024; ++i) {
buffer[i] = 'A' + (i % 26); // Fill with letters A-Z
}