मेमोरी लिमिटर

Android 17 और इसके बाद के वर्शन में, मेमोरी लिमिटर की सुविधा उपलब्ध है. यह एक सिस्टम सर्विस है, जो Linux cgroup v2 का इस्तेमाल करके, ऐप्लिकेशन की प्रोसेस के लिए मेमोरी के इस्तेमाल की निगरानी करती है और उस पर सीमाएं लागू करती है. मेमोरी लिमिटर, अलग-अलग ऐप्लिकेशन को सिस्टम की ज़्यादा मेमोरी इस्तेमाल करने से रोकता है. इससे, सिस्टम की मेमोरी पर पड़ने वाला लोड कम होता है. साथ ही, ज़रूरी प्रोसेस के लिए मेमोरी खत्म होने (OOM) की समस्या से बचा जा सकता है.

मैकेनिज़्म

मेमोरी लिमिटर, प्रोसेस के लाइफ़साइकल इवेंट और स्थिति में होने वाले बदलावों को ट्रैक करने के लिए, ऐक्टिविटी मैनेजर सर्विस (एएमएस) के साथ इंटिग्रेट होता है. मेमोरी लिमिटर, Linux कर्नल cgroup v2 फ़ाइल सिस्टम का इस्तेमाल करके, मेमोरी की सीमाएं लागू करता है.

मेमोरी लिमिटर का इस्तेमाल करने के लिए, डिवाइस के कर्नल में cgroup v2 और memory कंट्रोलर की सुविधा होनी चाहिए. यह सर्विस, खास तौर पर इन एट्रिब्यूट पर निर्भर करती है:

memory.high
यह एक सॉफ़्ट लिमिट है. अगर यह सीमा पार हो जाती है, तो प्रोसेस को थ्रॉटल किया जाता है. साथ ही, कर्नल उससे मेमोरी वापस पाने की कोशिश करता है.
memory.swap.max
इससे, स्वैप स्पेस की उस सीमा का पता चलता है जिसका इस्तेमाल प्रोसेस कर सकती है.

ऐप्लिकेशन पर असर

मेमोरी लिमिटर का असर उन ऐप्लिकेशन पर नहीं पड़ता जो अपनी मेमोरी की सीमाओं को पार नहीं करते.

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

अगर ऐप्लिकेशन, एनॉनिमस मेमोरी को असाइन करता रहता है और डिवाइस में स्वैप स्पेस खत्म हो जाता है, तो ऐप्लिकेशन को मेमोरी असाइन नहीं की जा सकती. इससे, ऐप्लिकेशन क्रैश हो सकता है.

प्रोसेस की निगरानी करना

मेमोरी लिमिटर, डिफ़ॉल्ट रूप से ऐप्लिकेशन की प्रोसेस (यूआईडी >= 10000) की निगरानी करता है. आम तौर पर, सिस्टम की प्रोसेस को निगरानी से छूट दी जाती है. इससे, सिस्टम की मुख्य स्थिरता की पुष्टि करने में मदद मिलती है.

मेमोरी लिमिटर, प्रोसेस की स्थिति के आधार पर मेमोरी की सीमाएं असाइन करता है:

  • विज़िबल प्रोसेस ऐसी स्थिति में होती हैं जहां वे उपयोगकर्ता को यूज़र इंटरफ़ेस (यूआई) दिखा सकती हैं. यूज़र इंटरफ़ेस (यूआई) दिखाते समय, किसी प्रोसेस से ज़्यादा रैम वर्किंग सेट का इस्तेमाल करने की उम्मीद की जा सकती है. इसलिए, उसे ज़्यादा मेमोरी की सीमा दी जाती है.

  • नॉन-विज़िबल प्रोसेस ऐसी स्थिति में होती हैं जहां वे ऐक्टिव तौर पर काम कर रही होती हैं, लेकिन यूज़र इंटरफ़ेस (यूआई) नहीं दिखा रही होती हैं. वे इस काम को करने के लिए मेमोरी का इस्तेमाल करती हैं, लेकिन यूज़र इंटरफ़ेस (यूआई) दिखाते समय उन्हें जितनी मेमोरी की ज़रूरत होती है उससे कम. इसलिए, उन्हें ज़्यादा पाबंदी वाली सीमा दी जाती है.

यहां दी गई टेबल में, प्रोसेस की अलग-अलग स्थितियों के हिसाब से मेमोरी की सीमाएं बताई गई हैं:

प्रोसेस की स्थितिमेमोरी की सीमा
PERSISTENTकोई पाबंदी नहीं है
PERSISTENT_UIकोई पाबंदी नहीं है
TOPज़्यादा लोगों को दिखे
BOUND_TOPज़्यादा लोगों को दिखे
FOREGROUND_SERVICEनहीं दिखेगा
BOUND_FOREGROUND_SERVICEनहीं दिखेगा
IMPORTANT_FOREGROUNDज़्यादा लोगों को दिखे
IMPORTANT_BACKGROUNDनहीं दिखेगा
TRANSIENT_BACKGROUNDनहीं दिखेगा
BACKUPनहीं दिखेगा
SERVICEनहीं दिखेगा
RECEIVERनहीं दिखेगा
TOP_SLEEPINGज़्यादा लोगों को दिखे
HEAVY_WEIGHTनहीं दिखेगा
HOMEनहीं दिखेगा
LAST_ACTIVITYनहीं दिखेगा
CACHED_ACTIVITYसंचित
CACHED_ACTIVITY_CLIENTसंचित
CACHED_RECENTसंचित
CACHED_EMPTYसंचित

कैश्ड स्थिति में, प्रोसेस फ़्रीज़ हो जाती हैं. इसके बाद, उन्हें ज़्यादा से ज़्यादा वापस पाया जाता है.

जब कोई प्रोसेस, असाइन की गई memory.high की सीमा को पार कर जाती है, तो मेमोरी लिमिटर उस इवेंट का पता लगाता है. साथ ही, डीबग करने से जुड़ी कार्रवाइयां ट्रिगर कर सकता है. जैसे, मेमोरी प्रोफ़ाइल कैप्चर करना या statsd में गड़बड़ी लॉग करना.

कॉन्फ़िगरेशन

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

  • फ़ाइल का पाथ: /vendor/etc/memory-limiter-config.xml

  • डिफ़ॉल्ट कॉन्फ़िगरेशन: अगर कॉन्फ़िगरेशन फ़ाइल नहीं मिलती है या उसे पढ़ा नहीं जा सकता या वह अमान्य है, तो मेमोरी लिमिटर बंद हो जाता है.

एक्सएमएल फ़ॉर्मैट

कॉन्फ़िगरेशन फ़ाइल, memory-limiter-config.xsd में तय किए गए स्कीमा के मुताबिक होती है. इस फ़ाइल की मदद से, सीमाओं के कई सेट तय किए जा सकते हैं. डिवाइस में उपलब्ध रैम के आधार पर, सर्विस सबसे सही सेट चुनती है. मेमोरी की सभी वैल्यू, मेबिबाइट (एमआईबी) में तय की जाती हैं.

<MemoryLimiterConfig>
  <version>1</version>
  <configList>
    <limitSet>
      <!-- Limits for a phone with at least 14G of ram: 8G/4G/4G/4G -->
      <minimumRequiredMemTotal>14336</minimumRequiredMemTotal>
      <memVisible>8192</memVisible>
      <memNotVisible>4096</memNotVisible>
      <swapVisible>4096</swapVisible>
      <swapNotVisible>4096</swapNotVisible>
    </limitSet>
  </configList>
</MemoryLimiterConfig>
version
यह एक पॉज़िटिव इंटिजर है, जो कॉन्फ़िगरेशन के वर्शन की पहचान करता है. यह 1 होना चाहिए.
minimumRequiredMemTotal
सीमाओं के इस सेट को मान्य करने के लिए, सिस्टम में कम से कम इतनी मेमोरी उपलब्ध होनी चाहिए.
memVisible
यह मेमोरी की वह सीमा (memory.high) है जो विज़िबल प्रोसेस के लिए तय की जाती है.
memNotVisible
यह मेमोरी की वह सीमा (memory.high) है जो नॉन-विज़िबल प्रोसेस के लिए तय की जाती है.
swapVisible
यह स्वैप की वह सीमा (memory.swap.max) है जो विज़िबल प्रोसेस के लिए तय की जाती है.
swapNotVisible
यह स्वैप की वह सीमा (memory.swap.max) है जो नॉन-विज़िबल प्रोसेस के लिए तय की जाती है.

डिवाइस की मेमोरी की सीमा से जुड़ी गाइडलाइन

अपने डिवाइस के लिए मेमोरी की सीमाएं कॉन्फ़िगर करते समय, इन गाइडलाइन को ध्यान में रखें:

  • हार्डवेयर की क्षमताओं के हिसाब से सीमाएं तय करना: डिवाइस बनाने वाली कंपनियां, अपने डिवाइस के हार्डवेयर की क्षमताओं के हिसाब से सीमाएं तय कर सकती हैं. Android, इन सीमाओं को सेट करने का सुझाव देता है:

    • विज़िबल प्रोसेस: कुल फ़िज़िकल रैम का कम से कम 1/2 और ज़्यादा से ज़्यादा 2/3.
    • नॉन-विज़िबल प्रोसेस: कुल फ़िज़िकल रैम का 1/4 से 1/3. डिवाइस बनाने वाली कंपनियां, डिवाइस की क्षमताओं और इस्तेमाल के मामलों के आधार पर अलग-अलग सीमाएं तय कर सकती हैं.
  • ऐप्लिकेशन के लिए रनटाइम एपीआई नहीं है: Android 17 (एसडीके 37) से, ऐप्लिकेशन के पास रनटाइम में मेमोरी की सीमाओं के बारे में क्वेरी करने के लिए कोई एपीआई नहीं है. डिवाइस बनाने वाली कंपनियों को इस बात का ध्यान रखना चाहिए. साथ ही, उन्हें बहुत कम सीमाएं तय नहीं करनी चाहिए. इससे यह पक्का किया जा सकेगा कि ऐप्लिकेशन, इस्तेमाल के सामान्य मामलों में सीमाओं को पार न करें.

  • यूनिवर्सल कॉन्फ़िगरेशन: ये सीमाएं, डिवाइस पर मौजूद ऐप्लिकेशन की सभी प्रोसेस पर लागू होती हैं. इनमें पहले से इंस्टॉल किए गए ऐप्लिकेशन भी शामिल हैं. कुछ ऐप्लिकेशन को इन सीमाओं से छूट देने के लिए, कोई अनुमति वाली सूची नहीं है.

कॉन्फ़िगरेशन में बदलाव करना

सिस्टम-वाइड सीमाओं में बदलाव करने के लिए, यह तरीका अपनाएं:

  1. /vendor/etc/memory-limiter-config.xml में बदलाव करें.
  2. बदलावों को लागू करने के लिए, डिवाइस को रीबूट करें या system_server को रीस्टार्ट करें.

Shell कमांड

am memory-limiter कमांड की मदद से, डेवलपर और आपके पास डेवलपमेंट और टेस्टिंग के लिए, रनटाइम में सर्विस के साथ इंटरैक्ट करने का विकल्प होता है:

am memory-limiter <SUB-COMMAND>

स्थिति

status सब-कमांड, मेमोरी लिमिटर की ऑपरेशनल स्थिति की रिपोर्ट करता है:

adb shell am memory-limiter status

आउटपुट का उदाहरण:

Memory limiter
  enabled                  monitoring=true          ignored=none
  visibleMem=1948MB        visibleSwap=974MB
  notVisibleMem=974MB      notVisibleSwap=487MB
  started=36               watched=36               watch-failed=0
  events=0                 processes=36             process-hwm=36

आउटपुट में ये मुख्य फ़ील्ड शामिल हैं:

monitoring
इससे पता चलता है कि लिमिटर, प्रोसेस पर नज़र रख रहा है या नहीं.
visibleMem और notVisibleMem
इनसे, हर स्थिति के लिए कैलकुलेट की गई मेमोरी की पूरी सीमाओं का पता चलता है.
events
इससे पता चलता है कि किसी प्रोसेस ने अपनी सीमा को कितनी बार पार किया है.
processes
इससे पता चलता है कि कितनी प्रोसेस की निगरानी की जा रही है.

ignore

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

adb shell am memory-limiter ignore 10087  // Ignore a specific UID
adb shell am memory-limiter ignore all    // Ignore all processes (effectively disables limiting)
adb shell am memory-limiter ignore none   // Resume normal operation

मैन्युअल

manual सब-कमांड की मदद से, किसी खास प्रोसेस (प्रोसेस आईडी या पीआईडी) के लिए कैलकुलेट की गई सीमाओं को, बाइट में तय की गई कस्टम वैल्यू से बदला जा सकता है. वैल्यू एक इंटिजर होनी चाहिए. हालांकि, इसमें एमआईबी के लिए "MB" सफ़िक्स या जीआईबी के लिए "GB" सफ़िक्स शामिल किया जा सकता है:

adb shell am memory-limiter manual 1234 1073741824 // Set a 1GiB limit for PID 1234
adb shell am memory-limiter manual 1234 1024MB     // Set a 1GiB limit for PID 1234
adb shell am memory-limiter manual 1234 1GB        // Set a 1GiB limit for PID 1234
adb shell am memory-limiter manual 1234 none       // Remove the manual override for PID 1234

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

मैन्युअल तौर पर किया गया कोई भी बदलाव, सिस्टम की मौजूदा सीमाओं से ज़्यादा नहीं हो सकता.