Android पर Unreal गेम की मेमोरी को ऑप्टिमाइज़ करना

Android गेम डेवलपमेंट में, मेमोरी का इस्तेमाल बहुत अहम होता है. Unreal Engine का इस्तेमाल करके गेम डेवलप करते समय, आपको मेमोरी की सीमाओं को पूरा करने के लिए, मेमोरी की स्थिति का लगातार विश्लेषण और ट्रैक करना होगा. इससे, मेमोरी लीक होने और ज़रूरत से ज़्यादा मेमोरी के इस्तेमाल को रोका जा सकेगा.

शेडर परमिटेशन कम करके मेमोरी बचाना

Lighting या Mobile Shader Permutation Reduction में इस्तेमाल न किए गए विकल्पों को हटाकर, शेडर परमिटेशन की संख्या कम की जा सकती है. इससे, ऐप्लिकेशन पैकेजिंग का साइज़ काफ़ी कम हो जाता है. साथ ही, पाइपलाइन स्टेट ऑब्जेक्ट (पीएसओ) की संख्या कम हो जाती है. इसके अलावा, रेंडर टारगेट या डमी टेक्सचर के इस्तेमाल को रोका जा सकता है. इससे, रनटाइम मेमोरी कम हो जाती है और परफ़ॉर्मेंस बेहतर होती है.

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

ऐसेट लोड करने की प्रोसेस को ऑप्टिमाइज़ करना

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

  • C++ कोड की परिभाषा और डेटा को अलग करना: मुख्य फ़ंक्शनैलिटी तय करें C++ कोड में UCLASS(Abstract) का इस्तेमाल करके, उन्हें असल डेटा से अलग करें.
  • इनहेरिटेंस को कम करना: डेटा सेटअप और ऐसेट लोड करने की प्रोसेस, सिर्फ़ लीफ़-नोड ब्लूप्रिंट में करें.
  • इनडायरेक्ट रेफ़रंस का इस्तेमाल करना: हार्ड रेफ़रंस से बचने के लिए, TSoftObjectPtrका इस्तेमाल करके, इनडायरेक्ट प्रॉपर्टी रेफ़रंस लागू करें. साथ ही, रनटाइम में ज़रूरत पड़ने पर ही, एसिंक्रोनस तरीके से ऐसेट लोड करें.
  • सावधानियां: एसिंक ऐसेट लोडिंग का इस्तेमाल करते समय, पक्का करें कि लोड होने की प्रोसेस पूरी होने पर, वैलिडिटी की जांच (IsValid) की जाए. इससे, डैंगलिंग पॉइंटर या क्रैश होने की समस्या से बचा जा सकता है.

ज़्यादा जानकारी के लिए, ऐसेट को रेफ़र करना और मोबाइल गेम बनाना UE5 की मदद से लेख पढ़ें.

स्मार्ट पॉइंटर और गार्बेज कलेक्शन (जीसी) को ट्यून करना

C++ डेवलपमेंट के दौरान, स्मार्ट पॉइंटर (जैसे, TSharedPtr और TWeakPtr) का इस्तेमाल करने से, डैंगलिंग पॉइंटर और मेमोरी लीक होने की समस्या से बचा जा सकता है. इसके अलावा, TWeakPtr का इस्तेमाल करने से, ऑब्जेक्ट के लिए मज़बूत रेफ़रंस नहीं बनते. इसलिए, गार्बेज कलेक्टर, ऑब्जेक्ट इकट्ठा करते समय रेफ़रंस की संख्या नहीं बढ़ाता. इससे, गैर-ज़रूरी ऑब्जेक्ट सर्वाइवल को रोका जा सकता है. साथ ही, रेफ़रंस ग्राफ़ की जटिलता कम हो जाती है. इससे, जीसी को ट्रैवर्स करने में लगने वाला समय कम हो जाता है और जीसी ओवरहेड काफ़ी कम हो जाता है. मोबाइल एनवायरमेंट में, गार्बेज कलेक्शन को असरदार तरीके से मैनेज किया जा सकता है. इसके लिए, लेवल ट्रांज़िशन या इनऐक्टिविटी के दौरान, ForceGarbageCollection को ट्रिगर करें. जैसे, जब उपयोगकर्ता का इंटरैक्शन न हो. इसके अलावा, इसे तब भी ट्रिगर किया जा सकता है, जब गेम किसी ऐसी स्थिति में हो जिसे समझा जा सकता है या बैकग्राउंड में चल रहा हो. उदाहरण के लिए, onStop कॉलबैक. इससे, यह पक्का किया जा सकता है कि ऐक्टिव गेमप्ले के अनुभव पर असर डाले बिना, गार्बेज कलेक्शन किया जाए.

ज़्यादा जानकारी के लिए, गार्बेज कलेक्शन और स्मार्ट पॉइंटर लेख पढ़ें.

रीलोकेशन टेबल कंप्रेस करके ऑप्टिमाइज़ करना

रीलोकेशन टेबल कंप्रेस करने का तरीका, ऑप्टिमाइज़ेशन का एक तरीका है. इससे, ईएलएफ़ बाइनरी में रीलोकेशन टेबल का साइज़ कंप्रेस किया जाता है, ताकि Android बाइनरी का साइज़ कम किया जा सके. जब Android minSDKVersion 23 या उससे ज़्यादा होता है, तब एपीएस रीलोकेशन टेबल कंप्रेस करने की सुविधा काम करती है. जब minSDKVersion 28 या उससे ज़्यादा होता है, तब आरईएलआर रीलोकेशन टेबल कंप्रेस करने की सुविधा भी काम करती है. इससे, .so फ़ाइल का साइज़ काफ़ी कम हो जाता है. इससे, डाउनलोड का साइज़ कम होता है. साथ ही, रनटाइम में .so mmap का मेमोरी फ़ुटप्रिंट भी कम हो जाता है. इससे, कुल फ़िज़िकल मेमोरी प्रेशर कम हो जाता है.

AndroidToolChain.cs

if (MinSDKVersion >= 28)
{
  Result += " -Wl,--pack-dyn-relocs=android+relr,--use-android-relr-tags";
}
else if (MinSDKVersion >= 23)
{
  Result += " -Wl,--pack-dyn-relocs=android";
}

इस ऑप्टिमाइज़ेशन को लागू करने के लिए, पक्का करें कि प्रोजेक्ट सेटिंग में रीलोकेशन टेबल को कंप्रेस करने की सुविधा चालू हो या bEnableAdvancedBinaryCompression वैरिएबल चालू हो.

यह देखने के लिए कि बाइनरी पर आरईएलआर कंप्रेस करने की सुविधा सही तरीके से लागू की गई है या नहीं, Android NDK से llvm-readelf टूल का इस्तेमाल करें.

llvm-readelf -d libUnreal.so | grep RELR

Unreal Engine के ThirdPerson टेंप्लेट को बनाने और dumpsys meminfo का इस्तेमाल करके मेज़र करने से, .so mmap के लिए पीएसएस और आरएसएस के इस्तेमाल में कमी की पुष्टि होती है.

कैटगरी कुल पीएसएस प्राइवेट डर्टी प्राइवेट क्लीन स्वैप डर्टी कुल आरएसएस
.so mmap कंप्रेस करने से पहले 1,70,210 24,360 1,41,564 0 2,42,204
.so mmap कंप्रेस करने के बाद 1,38,031 24,748 1,08,976 0 2,10,140

टेक्स्चर कंप्रेस करना

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

टेक्स्चर स्ट्रीमिंग को ऑप्टिमाइज़ करना

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