अपने ऐप्लिकेशन की मेमोरी मैनेज करना

इस पेज पर, ऐप्लिकेशन में मेमोरी के इस्तेमाल को कम करने का तरीका बताया गया है. Android ऑपरेटिंग सिस्टम, मेमोरी को कैसे मैनेज करता है, इस बारे में जानने के लिए मेमोरी मैनेजमेंट की खास जानकारी देखें.

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

अपने ऐप्लिकेशन के कोड और संसाधन के फ़ुटप्रिंट को कम करें

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

R8 को चालू करके, ऐप्लिकेशन का कुल साइज़ कम करें

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

R8 का इस्तेमाल करके, अपने ऐप्लिकेशन के मेमोरी फ़ुटप्रिंट को कम किया जा सकता है. R8 को आम तौर पर APK का साइज़ कम करने के लिए जाना जाता है. हालांकि, इसका सीधा और सकारात्मक असर रनटाइम मेमोरी (RAM) पर पड़ता है. R8, आपके ऐप्लिकेशन के बाइटकोड का विश्लेषण करता है, ताकि वह डेड कोड को हटा सके, एक जैसी क्लास को मर्ज कर सके, इनलाइन मेथड को मर्ज कर सके, और आइडेंटिफ़ायर को छोटा कर सके. यह APK से कम कंपाइल किया गया बाइटकोड, रैम में लोड करता है. इससे ऐप्लिकेशन के मेमोरी फ़ुटप्रिंट में कमी आती है. इसके अलावा, क्लास, मेथड, और फ़ील्ड के नामों को छोटे आइडेंटिफ़ायर में छोटा करने से, सीधे तौर पर रैम का इस्तेमाल कम हो जाता है. क्लास मर्जिंग और एक्सटेंसिव मेथड इनलाइनिंग जैसे ऑप्टिमाइज़ेशन, महंगे रनटाइम लुकअप और ऐलोकेशन पैटर्न को भी बदलते हैं. इससे हीप और स्टैक मेमोरी को ऑप्टिमाइज़ किया जाता है.

डेटा को सुरक्षित रखने से जुड़े नियमों के बारे में जानकारी

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

कोड कॉम्पोनेंट को लागू करने से जुड़े नियमों को सही तरीके से न लिखने पर, R8 आपके कोडबेस के बड़े हिस्से को ऑप्टिमाइज़ नहीं कर पाता. डेटा को सुरक्षित रखने के लिए, बहुत ज़्यादा समय तक लागू होने वाले नियमों का इस्तेमाल न करें. साथ ही, इन सबसे सही तरीकों को अपनाएं:

  • ग्लोबल नियमों का उल्लंघन करने से बचें:
    • -dontoptimize: इससे पूरे ऐप्लिकेशन के लिए ऑप्टिमाइज़ेशन की सुविधा बंद हो जाती है. इसलिए, एक्ज़ीक्यूटेबल फ़ाइलें बड़ी हो जाती हैं और उन्हें चलने में ज़्यादा समय लगता है.
    • -dontshrink: इससे इस्तेमाल न होने वाले कोड और संसाधनों को हटाने से रोका जाता है.
    • -dontobfuscate: इससे नाम को छोटा होने से रोका जाता है. साथ ही, मेमोरी की बचत करने का अहम फ़ायदा मिलता है. यह फ़ायदा खास तौर पर बड़े ऐप्लिकेशन में मिलता है.
  • पूरे पैकेज के लिए वाइल्डकार्ड का इस्तेमाल न करें: -keep class com.example.package.** { *; } जैसे ब्रॉड नियमों की वजह से, R8 को उस पैकेज में मौजूद हर क्लास, फ़ील्ड, और तरीके को सुरक्षित रखना पड़ता है. इससे R8, उस पैकेज में मौजूद कोड को हटाने, ऑप्टिमाइज़ करने या छोटा करने की सुविधा का इस्तेमाल नहीं कर पाएगा.

  • R8 की डिफ़ॉल्ट कॉन्फ़िगरेशन फ़ाइल का इस्तेमाल करें: हमेशा proguard-android-optimize.txt का इस्तेमाल करें.

डेटा को सुरक्षित रखने के नियमों के बारे में ज़्यादा जानने के लिए, डेटा को सुरक्षित रखने के नियमों की खास जानकारी देखें. इस्तेमाल किए जाने वाले और इस्तेमाल न किए जाने वाले खास पैटर्न के बारे में जानने के लिए, कीप के नियमों को लागू करने के सबसे सही तरीके लेख पढ़ें.

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

एक्सटर्नल लाइब्रेरी का इस्तेमाल करते समय सावधानी बरतें

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

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

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

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

डिपेंडेंसी इंजेक्शन के लिए, Hilt या Dagger 2 का इस्तेमाल करना

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

अगर आपको अपने ऐप्लिकेशन में डिपेंडेंसी इंजेक्शन फ़्रेमवर्क का इस्तेमाल करना है, तो Hilt या Dagger का इस्तेमाल करें. Hilt, Android के लिए एक डिपेंडेंसी इंजेक्शन लाइब्रेरी है. यह Dagger के ऊपर काम करती है. Dagger, आपके ऐप्लिकेशन के कोड को स्कैन करने के लिए रिफ़्लेक्शन का इस्तेमाल नहीं करता. Android ऐप्लिकेशन में, Dagger के स्टैटिक कंपाइल-टाइम इंप्लीमेंटेशन का इस्तेमाल किया जा सकता है. इससे रनटाइम में होने वाले खर्च या मेमोरी के इस्तेमाल पर कोई असर नहीं पड़ता.

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

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

इमेज लोड करने के लिए, मकसद तय करें

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

उदाहरण के लिए, ज़्यादातर बिटमैप ARGB_8888 कॉन्फ़िगरेशन का इस्तेमाल करते हैं. इसका मतलब है कि हर पिक्सल के लिए 4 बाइट मेमोरी की ज़रूरत होती है. इसमें लाल, हरे, नीले, और ऐल्फ़ा (पारदर्शिता) के लिए एक-एक बाइट मेमोरी की ज़रूरत होती है. अगर आपके पास 100 केबी का JPEG है और उसे 1000×1000 पिक्सल व्यू में दिखाया जाता है, तो बिटमैप को उन 10,00,000 पिक्सल में से हर पिक्सल के लिए 4 बाइट की ज़रूरत होगी. इससे 4 एमबी मेमोरी का इस्तेमाल होगा.

इमेज का इस्तेमाल बेहतर तरीके से करने के लिए, कई काम किए जा सकते हैं. उदाहरण के लिए, इमेज लोड करने वाली लाइब्रेरी का इस्तेमाल करने से, जब मेमोरी की ज़रूरत न हो, तब उसे रिलीज़ करने में मदद मिल सकती है. इमेज को बेहतर तरीके से मैनेज करने के बारे में जानकारी के लिए, बिटमैप इमेज को ऑप्टिमाइज़ करना लेख पढ़ें.

उपलब्ध मेमोरी और मेमोरी के इस्तेमाल की निगरानी करना

ऐप्लिकेशन की मेमोरी इस्तेमाल करने से जुड़ी समस्याओं को ठीक करने से पहले, आपको उनका पता लगाना होगा. Android Studio में मौजूद मेमोरी प्रोफ़ाइलर, मेमोरी से जुड़ी समस्याओं का पता लगाने और उन्हें ठीक करने में आपकी मदद करता है. इसके लिए, यह इन तरीकों का इस्तेमाल करता है:

मेमोरी प्रोफ़ाइलर, LeakCanary लीक डिटेक्शन लाइब्रेरी के साथ भी इंटिग्रेट होता है. LeakCanary का इस्तेमाल करके, मेमोरी लीक के विश्लेषण को टेस्ट डिवाइस से डेवलपमेंट मशीन पर ले जाया जा सकता है. इससे आपके वर्कफ़्लो को काफ़ी हद तक तेज़ किया जा सकता है. ज़्यादा जानकारी के लिए, Android Studio में हुए अपडेट की जानकारी देने वाला दस्तावेज़ देखें.

ऐसे अन्य टूल भी उपलब्ध हैं जिनका इस्तेमाल करके, मेमोरी से जुड़ी समस्याओं का पता लगाया जा सकता है. ये समस्याएं, प्रोडक्शन ऐप्लिकेशन का इस्तेमाल करने वाले लोगों के डेटा के आधार पर तय की जाती हैं:

इवेंट के जवाब में मेमोरी रिलीज़ करना

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

onTrimMemory() को लागू करते समय, आपको सिर्फ़ TRIM_MEMORY_UI_HIDDEN और TRIM_MEMORY_BACKGROUND इवेंट पर फ़ोकस करना चाहिए. (Android 14 से शुरू होने वाले वर्शन में, सिस्टम अब अन्य पुराने कॉन्स्टेंट के लिए सूचनाएं नहीं भेजता. इन कॉन्स्टेंट को Android 15 में आधिकारिक तौर पर बंद कर दिया गया है.)

  • TRIM_MEMORY_UI_HIDDEN: इस सिग्नल से पता चलता है कि आपके ऐप्लिकेशन का यूज़र इंटरफ़ेस (यूआई), उपयोगकर्ता की स्क्रीन से हट गया है. इस ट्रांज़िशन से, यूज़र इंटरफ़ेस (यूआई) से जुड़ी मेमोरी को रिलीज़ करने का मौका मिलता है. जैसे, बिटमैप, वीडियो चलाने के बफ़र या जटिल ऐनिमेशन रिसॉर्स.

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

इस कोड सैंपल में, मेमोरी से जुड़े अलग-अलग इवेंट के जवाब देने के लिए, onTrimMemory() कॉलबैक को लागू करने का तरीका बताया गया है:

Kotlin

import android.content.ComponentCallbacks2
// Other import statements.

class MainActivity : AppCompatActivity(), ComponentCallbacks2 {

    // Other activity code.

    /**
     * Release memory when the UI becomes hidden or when system resources become low.
     * @param level the memory-related event that is raised.
     */
    override fun onTrimMemory(level: Int) {

        if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
            // Release memory related to UI elements, such as bitmap caches.
        }

        if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
            // Release memory related to background processing, such as by
            // closing a database connection.
        }
    }
}

Java

import android.content.ComponentCallbacks2;
// Other import statements.

public class MainActivity extends AppCompatActivity
    implements ComponentCallbacks2 {

    // Other activity code.

    /**
     * Release memory when the UI becomes hidden or when system resources become low.
     * @param level the memory-related event that is raised.
     */
    public void onTrimMemory(int level) {

        if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
            // Release memory related to UI elements, such as bitmap caches.
        }

        if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
            // Release memory related to background processing, such as by
            // closing a database connection.
        }
    }
}

देखें कि आपको कितनी मेमोरी की ज़रूरत है

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

मेमोरी खत्म होने से बचने के लिए, सिस्टम से यह क्वेरी की जा सकती है कि मौजूदा डिवाइस पर कितना हीप स्पेस उपलब्ध है. इस आंकड़े के बारे में सिस्टम से पूछने के लिए, getMemoryInfo() पर कॉल करें. यह ActivityManager.MemoryInfo ऑब्जेक्ट दिखाता है. इससे डिवाइस की मौजूदा मेमोरी की स्थिति के बारे में जानकारी मिलती है. इसमें उपलब्ध मेमोरी, कुल मेमोरी, और मेमोरी थ्रेशोल्ड शामिल होता है. मेमोरी थ्रेशोल्ड, मेमोरी का वह लेवल होता है जिस पर सिस्टम प्रोसेस को रोकना शुरू कर देता है. ActivityManager.MemoryInfo ऑब्जेक्ट, lowMemory को भी दिखाता है. यह एक सामान्य बूलियन है, जिससे पता चलता है कि डिवाइस में मेमोरी कम है या नहीं.

यहां दिए गए कोड स्निपेट में, आपके ऐप्लिकेशन में getMemoryInfo() तरीके का इस्तेमाल करने का तरीका बताया गया है.

Kotlin

fun doSomethingMemoryIntensive() {

    // Before doing something that requires a lot of memory,
    // check whether the device is in a low memory state.
    if (!getAvailableMemory().lowMemory) {
        // Do memory intensive work.
    }
}

// Get a MemoryInfo object for the device's current memory status.
private fun getAvailableMemory(): ActivityManager.MemoryInfo {
    val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    return ActivityManager.MemoryInfo().also { memoryInfo ->
        activityManager.getMemoryInfo(memoryInfo)
    }
}

Java

public void doSomethingMemoryIntensive() {

    // Before doing something that requires a lot of memory,
    // check whether the device is in a low memory state.
    ActivityManager.MemoryInfo memoryInfo = getAvailableMemory();

    if (!memoryInfo.lowMemory) {
        // Do memory intensive work.
    }
}

// Get a MemoryInfo object for the device's current memory status.
private ActivityManager.MemoryInfo getAvailableMemory() {
    ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    activityManager.getMemoryInfo(memoryInfo);
    return memoryInfo;
}

कम मेमोरी की वजह से बंद होने वाले प्रोसेस पर नज़र रखना

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

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

मेमोरी से जुड़ी समस्याओं को ट्रैक करने के लिए ProfilingManager का इस्तेमाल करना

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

Android 17 के साथ दो नए ट्रिगर जोड़े गए हैं. ये खास तौर पर मेमोरी से जुड़ी समस्याओं का पता लगाने के लिए फ़ायदेमंद हैं:

  • TRIGGER_TYPE_OOM इससे पता चलता है कि ऐप्लिकेशन ने OutOfMemoryError थ्रो किया है. यह क्रैश होने के बाद ऐप्लिकेशन के अगली बार शुरू होने पर ट्रिगर होता है. ऐसा तब होता है, जब ऐप्लिकेशन, प्रोफ़ाइलिंग ट्रिगर के लिए रजिस्टर करता है.
  • TRIGGER_TYPE_ANOMALY यह तब ट्रिगर होता है, जब सिस्टम को ऐप्लिकेशन में गड़बड़ी का पता चलता है. यह गड़बड़ी, अन्य वजहों के साथ-साथ मेमोरी का ज़्यादा इस्तेमाल करने की वजह से भी हो सकती है. यह सूचना तब दिखती है, जब ऐप्लिकेशन बहुत ज़्यादा मेमोरी का इस्तेमाल कर रहा हो. साथ ही, यह सूचना तब दिखती है, जब सिस्टम, मेमोरी का ज़्यादा इस्तेमाल करने वाले ऐप्लिकेशन को बंद करने के लिए कोई कार्रवाई करने से पहले दिखती है. उदाहरण के लिए, अगर ऐप्लिकेशन Android 17 में तय की गई मेमोरी की सीमाओं से ज़्यादा मेमोरी इस्तेमाल करता है, तो सिस्टम के ऐप्लिकेशन को बंद करने से पहले TRIGGER_TYPE_ANOMALY ट्रिगर हो जाता है.

प्रोग्राम के हिसाब से ट्रिगर रजिस्टर करने और उन्हें वापस पाने के लिए, ProfilingManager का इस्तेमाल करने के बारे में ज़्यादा जानने के लिए, ट्रिगर पर आधारित प्रोफ़ाइलिंग का दस्तावेज़ देखें.

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

मेमोरी का कम इस्तेमाल करने वाले कोड कंस्ट्रक्ट का इस्तेमाल करें

Android की कुछ सुविधाओं, Java क्लास, और कोड कंस्ट्रक्ट में दूसरों की तुलना में ज़्यादा मेमोरी का इस्तेमाल होता है. अपने कोड में ज़्यादा बेहतर विकल्प चुनकर, अपने ऐप्लिकेशन के लिए इस्तेमाल की जाने वाली मेमोरी को कम किया जा सकता है.

सेवाओं का कम से कम इस्तेमाल करना

हमारा सुझाव है कि जब सेवाओं की ज़रूरत न हो, तब उन्हें चालू न रखें. गैर-ज़रूरी सेवाओं को चालू रखना, मेमोरी मैनेजमेंट से जुड़ी सबसे खराब गलतियों में से एक है. कोई Android ऐप्लिकेशन ऐसी गलती कर सकता है. अगर आपके ऐप्लिकेशन को बैकग्राउंड में काम करने के लिए किसी सेवा की ज़रूरत है, तो उसे तब तक चालू न रखें, जब तक उसे कोई काम न करना हो. सेवा का इस्तेमाल तब तक करें, जब तक वह अपना टास्क पूरा न कर ले. ऐसा न करने पर, मेमोरी लीक हो सकती है.

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

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

ऑप्टिमाइज़ किए गए डेटा कंटेनर का इस्तेमाल करना

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

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

अगर ज़रूरी हो, तो डेटा स्ट्रक्चर को छोटा करने के लिए, हमेशा रॉ ऐरे पर स्विच किया जा सकता है.

कोड ऐब्स्ट्रैक्शन का इस्तेमाल सावधानी से करें

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

सीरियलाइज़ किए गए डेटा के लिए, लाइट प्रोटोबफ़ का इस्तेमाल करना

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

ज़्यादा जानकारी के लिए, protobuf readme देखें.

मेमोरी लीक से सावधान रहें

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

ज़्यादा जानकारी के लिए, मेमोरी लीक देखें.

मेमोरी चर्न से बचना

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

अक्सर, मेमोरी चर्न की वजह से, गार्बेज कलेक्शन के कई इवेंट हो सकते हैं. असल में, मेमोरी चर्न से पता चलता है कि किसी तय समय में, कितने अस्थायी ऑब्जेक्ट असाइन किए गए.

उदाहरण के लिए, किसी for लूप में एक से ज़्यादा अस्थायी ऑब्जेक्ट असाइन किए जा सकते हैं. इसके अलावा, व्यू के onDraw() फ़ंक्शन में नए Paint या Bitmap ऑब्जेक्ट बनाए जा सकते हैं. इन दोनों ही मामलों में, ऐप्लिकेशन बहुत कम समय में बड़ी संख्या में ऑब्जेक्ट बनाता है. ये ऑब्जेक्ट, जनरेशन में उपलब्ध पूरी मेमोरी का इस्तेमाल कर सकते हैं. इससे गार्बेज कलेक्शन इवेंट ट्रिगर हो सकता है.

मेमोरी प्रोफ़ाइलर का इस्तेमाल करके, अपने कोड में उन जगहों का पता लगाएं जहां मेमोरी का इस्तेमाल ज़्यादा होता है. इससे आपको समस्याओं को ठीक करने में मदद मिलेगी.

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

यह भी देखा जा सकता है कि ऑब्जेक्ट पूल, इस्तेमाल के उदाहरण के लिए फ़ायदेमंद हैं या नहीं. ऑब्जेक्ट पूल की मदद से, किसी ऑब्जेक्ट इंस्टेंस को फ़्लोर पर छोड़ने के बजाय, उसे पूल में रिलीज़ किया जाता है. ऐसा तब किया जाता है, जब उसकी ज़रूरत नहीं होती. अगली बार जब उस टाइप के किसी ऑब्जेक्ट इंस्टेंस की ज़रूरत होगी, तब उसे ऐलोकेट करने के बजाय पूल से हासिल किया जा सकता है.

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

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