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

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

मैकेनिज़्म

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

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

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

ऐप्लिकेशन पर पड़ने वाला असर

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

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

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

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

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

<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) है जो नहीं दिखने वाली प्रोसेस के लिए तय की जाती है.

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

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

  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

manual सब-कमांड की मदद से, किसी खास प्रोसेस (प्रोसेस आईडी या पीआईडी के हिसाब से) के लिए, कैलकुलेट की गई सीमाओं को मेगाबाइट (एमबी) में कस्टम वैल्यू के साथ बदला जा सकता है:

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

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