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

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

रैंडम-ऐक्सेस मेमोरी (रैम), सॉफ़्टवेयर डेवलपमेंट के किसी भी एनवायरमेंट के लिए एक अहम संसाधन है. यह मोबाइल ऑपरेटिंग सिस्टम के लिए और भी ज़्यादा अहम है, जहाँ फ़िज़िकल मेमोरी अक्सर सीमित होती है. Android रनटाइम (एआरटी) और 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 के आधार पर बंद कर देता है. जिन ऐप्लिकेशन को कैश किया जाता है या जो बिना किसी यूज़र इंटरफ़ेस (यूआई) के सेवा चलाते हैं (जैसे कि कोई जॉब), उनके स्कोर सबसे ज़्यादा होते हैं और उन्हें सबसे पहले बंद किया जाता है. अगर मेमोरी बहुत कम रहती है, तो डेमॉन को 0 के oom_adj_score वाली प्रोसेस से मेमोरी वापस लेने के लिए मजबूर किया जाता है. यह स्कोर, दिखने वाले ऐप्लिकेशन के लिए रिज़र्व होता है. इसलिए, उन्हें बंद करने से प्रोसेस तुरंत बंद हो जाती है. इससे उपयोगकर्ता को लगता है कि ऐप्लिकेशन क्रैश हो गया है. इससे, लाइफ़साइकल की स्थिति को सेव करने वाले स्टैंडर्ड तरीकों को अक्सर बायपास कर दिया जाता है. साथ ही, उपयोगकर्ता की प्रोग्रेस का डेटा मिट जाता है.

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 ऑब्जेक्ट बनाए हों. इन दोनों ही मामलों में, ऐप्लिकेशन बहुत कम समय में बड़ी संख्या में ऑब्जेक्ट बनाता है. इससे, यंग जनरेशन में उपलब्ध मेमोरी बहुत तेज़ी से खत्म हो सकती है. इसलिए, गार्बेज कलेक्शन इवेंट ट्रिगर हो जाता है.

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

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

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

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

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