kswapd और lmkd के बीच इंटरैक्शन

इस पेज पर, Android पर kswapd और lmkd के बीच होने वाले इंटरैक्शन के बारे में बताया गया है. साथ ही, यह भी बताया गया है कि ये दोनों मेमोरी प्रेशर को मैनेज करने के लिए, एक साथ कैसे काम करते हैं.

बैकग्राउंड

सिस्टम में मेमोरी कम होने पर, Android दो मुख्य तरीकों से मेमोरी को वापस हासिल करता है:

  1. kswapd: यह एक स्टैंडर्ड Linux कर्नेल डीमन है, जो क्लीन फ़ाइल-बैक्ड पेजों को हटाकर या एनॉनिमस पेजों को ZRAM में स्वैप करके, पेजों को फिर से हासिल करता है.
  2. lmkd: Android का यूज़रस्पेस लो मेमोरी किलर डीमन. जब kswapd, मेमोरी की ज़रूरतों को पूरा नहीं कर पाता और सिस्टम पर दबाव बढ़ता है (जैसा कि पीएसआई से पता चलता है), तो lmkd प्रोसेस को बंद कर देता है, ताकि मेमोरी का ज़्यादा हिस्सा खाली हो सके.

kswapd और lmkd, मेमोरी को फिर से इस्तेमाल करने के लिए बनाए गए दो सिस्टम हैं. दोनों का मकसद एक ही होता है (मेमोरी खाली करना), लेकिन दोनों अलग-अलग तरीके से काम करते हैं. तुलना करने और अंतर बताने के लिए:

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

ओओएम स्कोर बकेट

Android, उपयोगकर्ता के लिए प्रोसेस की अहमियत के आधार पर, आउट-ऑफ़-मेमोरी (ओओएम) स्कोर अडजस्टमेंट (oom_score_adj) असाइन करता है. ज़्यादा स्कोर वाली प्रोसेस सबसे पहले बंद की जाती हैं.

आम तौर पर इस्तेमाल होने वाली बकेट में ये शामिल हैं:

  • कैश मेमोरी में सेव की गई प्रोसेस (स्कोर >= 900): ऐसी प्रोसेस जिनकी फ़िलहाल ज़रूरत नहीं है. इन्हें इसलिए सेव किया जाता है, ताकि ज़रूरत पड़ने पर इन्हें तेज़ी से रीस्टार्ट किया जा सके.
  • सेवा (स्कोर 500): यह प्रोसेस, शुरू की गई सेवाओं को होस्ट करती है.
  • फ़ोरग्राउंड सेवा (स्कोर 200): फ़ोरग्राउंड सेवाओं को होस्ट करने वाली प्रोसेस.
  • फ़ोरग्राउंड (स्कोर 0): वह ऐप्लिकेशन जिसके साथ उपयोगकर्ता फ़िलहाल इंटरैक्ट कर रहा है.

ज़्यादा जानकारी: पीएसआई और एलएमकेडी ट्रिगर करना

पीएसआई क्या है?

प्रेशर स्टॉल इन्फ़ॉर्मेशन (पीएसआई), Linux कर्नेल की एक सुविधा है. यह रिसॉर्स की कमी को मापने का एक स्टैंडर्ड तरीका उपलब्ध कराती है. यह सीपीयू, मेमोरी, और I/O की कमी की वजह से, टास्क में होने वाली देरी को ट्रैक करता है.

मेमोरी पीएसआई: "कुछ" बनाम "पूरा"

मेमोरी पीएसआई, खास तौर पर मेमोरी की कमी की वजह से होने वाली देरी को ट्रैक करता है. जैसे, पेज को फिर से वापस पाने या फिर से गड़बड़ी होने का इंतज़ार करना. इसमें दो मेट्रिक होती हैं:

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

पीएसआई, एलएमकेडी को कैसे ट्रिगर करता है

उपयोगकर्ता स्पेस lmkd डीमन, कर्नेल के साथ रजिस्टर होता है, ताकि पीएसआई थ्रेशोल्ड के पार होने पर सूचनाएं मिल सकें. इसके लिए, /proc/pressure/memory को मॉनिटर किया जाता है. जब सिस्टम में मेमोरी का दबाव ज़्यादा होता है (उदाहरण के लिए, full स्टॉल, कॉन्फ़िगर की गई अवधि से ज़्यादा हो जाता है), तो कर्नेल lmkd को चालू कर देता है. इसके बाद, lmkd सिस्टम की स्थिति का आकलन करता है और तय करता है कि प्रोसेस को बंद करना है या नहीं. साथ ही, यह तय करता है कि ओओएम स्कोर और साइज़ के आधार पर किन प्रोसेस को बंद करना है.

LMKD ट्यूनिंग

सिस्टम प्रॉपर्टी का इस्तेमाल करके, एलएमकेडी के काम करने के तरीके को ट्यून किया जा सकता है.

किसी डिवाइस पर ट्यूनिंग वैल्यू ढूंढना

कनेक्ट किए गए डिवाइस पर, मौजूदा एलएमकेडी ट्यूनिंग वैल्यू देखी जा सकती हैं. इसके लिए, यह कमांड चलाएं:

adb shell getprop | grep lmk

सामान्य LMKD प्रॉपर्टी

यहां कुछ मुख्य प्रॉपर्टी दी गई हैं, जिनका इस्तेमाल एलएमकेडी को ट्यून करने के लिए किया जाता है. पूरी सूची देखने के लिए, Android दस्तावेज़ देखें:

  • ro.lmk.use_psi: मेमोरी प्रेशर का पता लगाने के लिए, पीएसआई मॉनिटर का इस्तेमाल करने के लिए, इसे true पर सेट करें. यह Android 10 और इसके बाद के वर्शन पर डिफ़ॉल्ट रूप से सेट होता है.
  • ro.lmk.psi_partial_stall_ms: some (आंशिक) स्टॉल की अवधि के लिए थ्रेशोल्ड, मिलीसेकंड में. इसके बाद, किल ट्रिगर होता है. सामान्य डिवाइसों पर डिफ़ॉल्ट रूप से 70 मि॰से॰ और कम रैम वाले डिवाइसों पर 200 मि॰से॰.
  • ro.lmk.psi_complete_stall_ms: full के रुकने की अवधि के लिए थ्रेशोल्ड, मिलीसेकंड में. इससे, प्रोसेस को बंद करने की सुविधा ट्रिगर होती है. डिफ़ॉल्ट रूप से, यह 700 मि॰से॰ पर सेट होता है.
  • ro.lmk.kill_heaviest_task: अगर true, तो एलएमकेडी, एक ही ओओएम बकेट में मौजूद कैंडिडेट में से सबसे ज़्यादा मेमोरी का इस्तेमाल करने वाली प्रोसेस को बंद कर देता है.

टेस्ट डिवाइस (Google Pixel 8 Pro) पर ट्यूनिंग की ज़रूरी वैल्यू

(ध्यान दें: Android 15 वाले हाई-एंड डिवाइसों के लिए, आम तौर पर ये डिफ़ॉल्ट वैल्यू होती हैं)

  • ro.lmk.use_psi: true
  • ro.lmk.psi_partial_stall_ms: 70 (सामान्य)
  • ro.lmk.psi_complete_stall_ms: 700 (सामान्य)
  • ro.lmk.kill_heaviest_task: true

ZRAM और स्वैप की पुष्टि

ZRAM की क्षमता से इस बात पर काफ़ी असर पड़ता है कि स्वैप कितनी तेज़ी से भरता है और एलएमकेडी किल को ट्रिगर करता है. इन कमांड का इस्तेमाल करके, डिवाइस पर ZRAM और स्वैप स्टेटस देखा जा सकता है:

# Check ZRAM sizing and usage
adb shell free -m

# Check swap partition details
adb shell cat /proc/swaps

प्रैक्टिकल एक्सरसाइज़: kswapd और lmkd को ट्रिगर करना

इस एक्सरसाइज़ में, KswapdLmkdLab सैंपल ऐप्लिकेशन का इस्तेमाल करके, अलग-अलग ओओएम बकेट में प्रोसेस बनाई जाएंगी. इसके बाद, मुख्य प्रोसेस में मेमोरी का इस्तेमाल करके, kswapd और lmkd को ट्रिगर किया जाएगा.

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

1. सब-प्रोसेस बनाना

लॉन्च होने पर, ऐप्लिकेशन अपने-आप ये सबप्रोसेस शुरू करता है:

  • कैश मेमोरी में सेव की गई प्रोसेस (oom_score_adj >= 900)
  • Service Process (oom_score_adj 500)
  • फ़ोरग्राउंड सर्विस प्रोसेस (oom_score_adj 200)

एडीबी का इस्तेमाल करके, प्रोसेस और उनके ओओएम स्कोर की पुष्टि करें:

adb shell dumpsys activity processes | grep com.android.kswapdlmkdlab

आउटपुट स्निपेट का सैंपल:

    Proc #  0: fg       T/A/TOP  LCMNFUATI  t: 0 18959:com.android.kswapdlmkdlab/u0a358 (top-activity)
    Proc #  1: prcp     b/ /FGS  -------TI  t: 0 19050:com.android.kswapdlmkdlab:foreground/u0a358 (fg-service)
    Proc #  2: svc      b/ /SVC  -------TI  t: 0 19077:com.android.kswapdlmkdlab:service/u0a358 (started-services)
    Proc #  3: cch      b/ /CACC -------TI  t: 0 19014:com.android.kswapdlmkdlab:cached/u0a358 (cch-client-act)

प्रोसेस की स्थिति के लिए इस्तेमाल किए जाने वाले शॉर्ट फ़ॉर्म का मतलब:

  • fg: फ़ोरग्राउंड (ओओएम स्कोर 0)
  • prcp: साफ़ तौर पर दिखने वाली (फ़ोरग्राउंड सर्विस, ओओएम स्कोर 200)
  • svc: सेवा शुरू की गई (ओओएम स्कोर 500)
  • cch: कैश मेमोरी में सेव की गई प्रोसेस (ओओएम स्कोर 900)

2. मेमोरी प्रेशर को ट्रिगर करना

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

सबप्रोसेस बंद होने की निगरानी करना

ऐप्लिकेशन, IBinder.linkToDeath तरीके का इस्तेमाल करके इन सबप्रोसेस के बंद होने पर नज़र रखता है:

  1. मुख्य प्रोसेस, bindService का इस्तेमाल करके टारगेट प्रोसेस में किसी सेवा से जुड़ती है.
  2. कनेक्ट होने पर, यह सेवा को दिखाने वाला IBinder ऑब्जेक्ट हासिल करता है.
  3. यह बाइंडर पर linkToDeath को कॉल करके, IBinder.DeathRecipient को रजिस्टर करता है.
  4. जब टारगेट प्रोसेस बंद हो जाती है (उदाहरण के लिए, जब एलएमकेडी उसे बंद कर देता है), तो सिस्टम binderDied() तरीके को कॉल करता है. इससे ऐप्लिकेशन, बंद होने के इवेंट को एसिंक्रोनस तरीके से रिकॉर्ड कर पाता है.

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

सैंपल के तौर पर मिला ऐप्लिकेशन इस्तेमाल करने का तरीका

यहां Google Pixel 8 Pro पर टेस्ट रन पूरा होने के बाद, ऐप्लिकेशन का स्क्रीनशॉट दिया गया है. इस डिवाइस में कुल रैम करीब 12 जीबी है.

टेस्ट रन पूरा होने के बाद, सैंपल के तौर पर मिले ऐप्लिकेशन का स्क्रीनशॉट.
पहली इमेज. Pixel 8 Pro पर टेस्ट रन पूरा होने के बाद, सैंपल के तौर पर मिला ऐप्लिकेशन.

Perfetto ट्रेस का विश्लेषण

इंटरैक्शन को कैप्चर करने के लिए, Perfetto के इस कॉन्फ़िगरेशन का इस्तेमाल करें. इससे शेड्यूलिंग, मेमोरी काउंटर, एलएमके किल, और प्रेशर स्टॉल इन्फ़ॉर्मेशन (पीएसआई) को कैप्चर किया जा सकता है.

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

Perfetto को शेड्यूल करने, मेमोरी काउंटर, एलएमके किल, और प्रेशर स्टॉल इन्फ़ॉर्मेशन (पीएसआई) के साथ चलाकर, इंटरैक्शन को कैप्चर करें:

adb shell perfetto -c - --txt -o /data/misc/perfetto-traces/kswapd_lmkd.perfetto-trace <<EOF
buffers: { size_kb: 131072 }
data_sources: {
    config {
        name: "linux.ftrace"
        ftrace_config {
            ftrace_events: "lowmemorykiller/lowmemory_kill"
            ftrace_events: "vmscan/mm_vmscan_kswapd_wake"
            ftrace_events: "vmscan/mm_vmscan_kswapd_sleep"
            ftrace_events: "psi/psi_event"
        }
    }
}
duration_ms: 180000
EOF

ट्रेस की समीक्षा करना

यहां दिया गया स्क्रीनशॉट, ट्रेस से लिया गया है. इसमें :cached (सबसे ज़्यादा किल होने वाली) प्रोसेस के किल होने से ठीक पहले से लेकर, :foreground (सबसे कम किल होने वाली) प्रोसेस के किल होने तक की समयावधि दिखाई गई है.

Perfetto यूज़र इंटरफ़ेस (यूआई) का स्क्रीनशॉट, जिसमें kswapd और lmkd की गतिविधि दिख रही है.
दूसरी इमेज. Perfetto ट्रेस, जिसमें kswapd रिक्लेम और lmkd किल्स दिख रहे हैं.

MemFree पहले से ही काफ़ी कम है और इस पर लगातार दबाव बना हुआ है. kswapd लगातार काम कर रहा है और सभी kswapdlmkdlab प्रोसेस (मुख्य प्रोसेस और सब-प्रोसेस) से mem.rss.file पेज हटाकर और mem.rss.anon को mem.swap पर ले जाकर दबाव कम कर रहा है. ऐसा हो सकता है कि यह उन अन्य प्रोसेस से भी दबाव कम कर रहा हो जो इस स्क्रीनशॉट में नहीं दिखाई गई हैं. साथ ही, kswapdlmkdlab ऐप्लिकेशन मेमोरी का इस्तेमाल करता रहता है. इससे मेमोरी पर दबाव बढ़ता है और kswapd उसे वापस नहीं ले पाता.

जब दबाव बहुत ज़्यादा हो जाता है, जैसा कि कुछ समय के लिए psi.mem के ज़्यादा होने पर दिखता है, तो lmkd चालू हो जाता है और कुछ प्रोसेस को बंद कर देता है. आपको दिखेगा कि lmkd, ओओएम स्कोर का पालन करता है. यह सबसे पहले kswapdlmkdlab:cached को बंद करता है, फिर :service को, और फिर :foreground को.

इवेंट की टाइमलाइन देखें और इन बातों पर विचार करें:

  • kswapd और lmkd एक-दूसरे के पूरक कैसे हैं: मेमोरी पर दबाव पड़ने पर, kswapd सबसे पहले जवाब देता है. हालांकि, जब kswapd का रीक्लेम बैंडविड्थ, ऐलोकेशन की मांग को पूरा नहीं कर पाता, तब lmkd मदद करता है.
  • मेमोरी खाली होने की दर: kswapd में खर्च किए गए सीपीयू समय को देखें. साथ ही, mem.rss.file को हटाकर या mem.rss.anon को mem.swap से स्वैप करके, वापस ली जा रही मेमोरी को देखें. इसकी तुलना lmkd में कुछ समय के लिए होने वाली गतिविधि से करें. इसकी वजह से, प्रोसेस की निजी मेमोरी का बड़ा हिस्सा रिलीज़ हो जाता है.

क्वेरी

अपने ट्रेस से डेटा निकालने के लिए, Perfetto यूज़र इंटरफ़ेस (यूआई) (क्वेरी एसक्यूएल) में ये क्वेरी चलाएं.

1. kswapd गतिविधि

कर्नेल का स्वैप डीमन कब चालू था और चल रहा था, यह जानने के लिए यह कमांड चलाएं:

SELECT ts, dur, state
FROM thread_state
JOIN thread USING (utid)
WHERE thread.name LIKE 'kswapd%'
  AND state = 'Running'
LIMIT 5;

आउटपुट का सैंपल:

ts dur राज्य
30317633052969 159180 चालू
30317633398347 3999186 चालू
30317638448111 1847941 चालू
30317641455354 1031006 चालू
30317643272615 888387 चालू

2. एलएमकेडी किल्स

एलएमकेडी, कम मेमोरी की वजह से बंद की गई प्रोसेस को instant टेबल में सेव करता है. सभी एलएमकेडी किल के बारे में क्वेरी करने के लिए:

SELECT ts, name
FROM instant
WHERE name LIKE 'lmk,%'
ORDER BY ts ASC;

इवेंट के नाम का फ़ॉर्मैट यह है: lmk,<pid>,<kill_reason>,<oom_score_adj>,<min_oom_score>,<max_thrashing>.

  • kill_reason: यह एक इंटीजर है, जो बताता है कि lmkd ने प्रोसेस को बंद करने का फ़ैसला क्यों लिया (system/memory/lmkd/statslog.h में बताया गया है):
    • 0: PRESSURE_AFTER_KILL
    • 1: NOT_RESPONDING
    • 2: LOW_SWAP_AND_THRASHING (ZRAM में जगह बनाने के लिए बहुत कम जगह बची है और थ्रैशिंग हुई है)
    • 3: LOW_MEM_AND_SWAP (सिस्टम में खाली मेमोरी और ZRAM स्वैप, दोनों कम हैं)
    • 4: LOW_MEM_AND_THRASHING
    • 5: DIRECT_RECL_AND_THRASHING
    • 6: LOW_MEM_AND_SWAP_UTIL
    • 7: LOW_FILECACHE_AFTER_THRASHING
    • 8: LOW_MEM
    • 9: DIRECT_RECL_STUCK
  • max_thrashing: प्रोसेस बंद होने के समय, पेज थ्रैशिंग का ज़्यादा से ज़्यादा प्रतिशत.

आउटपुट का सैंपल:

ts नाम
30326148679967 lmk,2308,3,900,201,0
30330439763710 lmk,2309,3,500,201,0
30334985999837 lmk,2310,2,200,0,307

विज़ुअलाइज़ेशन

डेटा को विज़ुअलाइज़ करने के लिए, यहां दी गई gnuplot स्क्रिप्ट का इस्तेमाल किया जा सकता है. इससे सिस्टम की खाली मेमोरी, kswapd गतिविधि, lmkd किल्स, और पीएसआई को एक ही टाइम सीरीज़ पर प्लॉट किया जा सकता है. स्क्रिप्ट यह मानती है कि इसे Android बिल्ड की टॉप डायरेक्ट्री से चलाया गया है.

आउटपुट प्लॉट का सैंपल

यहां दिया गया प्लॉट, सैंपल डेटा के साथ ऊपर दी गई स्क्रिप्ट का इस्तेमाल करके जनरेट किया गया था. यह डेटा, टेस्ट रन को दिखाता है.

खाली मेमोरी, kswapd गतिविधि, पीएसआई, और lmkd किल का प्लॉट.
तीसरी इमेज. मेमोरी प्रेशर प्लॉट में खाली मेमोरी, kswapd, पीएसआई, और lmkd किल्स दिख रहे हैं.

प्लॉट के बारे में जानकारी:

इस प्लॉट में, स्ट्रेस टेस्ट के दौरान मेमोरी मैनेज करने वाले अलग-अलग कॉम्पोनेंट के बीच डाइनैमिक इंटरैक्शन को दिखाया गया है:

  1. खाली मेमोरी में गिरावट: मुख्य ऐप्लिकेशन के मेमोरी इस्तेमाल करने पर, सिस्टम की खाली मेमोरी (बैंगनी लाइन) लगातार कम होती जाती है.
  2. kswapd चालू होना: जब खाली मेमोरी कुछ वॉटरमार्क से कम हो जाती है, तो kswapd चालू हो जाता है (नीली तरंगें). इससे ZRAM में स्वैप करके मेमोरी वापस मिल जाती है. यह रुक-रुककर होने वाली बढ़ोतरी के तौर पर दिखता है.
  3. पीएसआई स्पाइक: जब kswapd को मेमोरी के बंटवारे की ज़्यादा दर को मैनेज करने में मुश्किल होती है, तो थ्रेड मेमोरी के बंटवारे पर रुकने लगते हैं. इससे पीएसआई (प्रेशर स्टॉल इन्फ़ॉर्मेशन) (हरी लाइन) में बढ़ोतरी होती है.
  4. एलएमकेडी किल्स: जब पीएसआई गंभीर लेवल पर पहुंच जाता है (उदाहरण के लिए, सैद्धांतिक तौर पर ro.lmk.psi_complete_stall_ms थ्रेशोल्ड से ज़्यादा) और खाली मेमोरी बहुत कम होती है, तो lmkd कम प्राथमिकता वाली प्रोसेस (30 और 45 समय पर ऑरेंज इंपल्स) को बंद करके, मेमोरी के बड़े हिस्से को खाली कर देता है. ध्यान दें कि प्रोसेस को बंद करने के तुरंत बाद, खाली मेमोरी बढ़ जाती है और पीएसआई कम हो जाता है. इससे पता चलता है कि प्रोसेस को बंद करने से, मेमोरी पर दबाव कम करने में मदद मिलती है. ________________________________________________________________________________

← मेमोरी को फिर से इस्तेमाल करना: मेमोरी को खाली करना और स्वैप करना | ↑ ऊपर जाएं | मेमोरी पेजों को ओएस को वापस करना →