تعامل kswapd و lmkd

این صفحه به تعامل بین kswapd و lmkd در اندروید می‌پردازد و نحوه همکاری آنها برای مدیریت فشار حافظه را نشان می‌دهد.

پیشینه

اندروید از دو مکانیسم اصلی برای بازیابی حافظه در مواقع کمبود حافظه سیستم استفاده می‌کند:

  1. kswapd : یک سرویس استاندارد هسته لینوکس که با حذف صفحات پاک‌شده یا انتقال صفحات ناشناس به ZRAM، صفحات را بازیابی می‌کند.
  2. lmkd : دیمن از بین برنده‌ی کمبود حافظه در فضای کاربری اندروید. وقتی kswapd نمی‌تواند با نیازهای حافظه همگام شود و فشار سیستم افزایش می‌یابد (همانطور که توسط PSI نشان داده می‌شود)، lmkd برای از بین بردن فرآیندها و آزاد کردن بخش‌های بزرگتری از حافظه وارد عمل می‌شود.

kswapd و lmkd دو سیستم بازیابی حافظه مکمل هستند. آنها برای رسیدن به یک هدف (ایجاد حافظه آزاد) اما با روش‌های مختلف کار می‌کنند. برای مقایسه و بررسی:

  • قابل بازیابی در مقابل مخرب : kswapd صفحات حافظه‌ای را که می‌توانند از حافظه خوانده شوند، حذف می‌کند، یا صفحات حافظه را به پارتیشن‌های حافظه یا حافظه دیگری که می‌توانند بنا به تقاضا خوانده شوند، منتقل می‌کند. lmkd فرآیندها را از بین می‌برد، که حالت غیرفرار را از بین می‌برد.
  • بازپس‌گیری پهنای باند : kswapd برای بازپس‌گیری مقدار مشخصی از حافظه آزاد، نسبت به lmkd ، پردازنده بیشتری مصرف می‌کند و بازپس‌گیری حافظه مذکور زمان بیشتری می‌برد. lmkd می‌تواند مقادیر زیادی از حافظه را در فواصل کوتاه و با تلاش نسبتاً کم بازپس بگیرد. در نظر داشته باشید که در دستگاه‌های تلفن همراه، تلاش پردازنده نه تنها به تأخیر، بلکه به مصرف باتری نیز منجر می‌شود.

دسته‌های امتیاز OOM

اندروید بر اساس اهمیت فرآیندها برای کاربر، یک تنظیم امتیاز کمبود حافظه (OOM) ( oom_score_adj ) به آنها اختصاص می‌دهد. فرآیندهایی که امتیاز بالاتری دارند، ابتدا بسته می‌شوند.

سطل‌های رایج عبارتند از:

  • ذخیره شده در حافظه پنهان (امتیاز >= ۹۰۰): فرآیندهایی که در حال حاضر مورد نیاز نیستند، برای راه‌اندازی مجدد سریع‌تر نگه داشته می‌شوند.
  • سرویس (امتیاز ۵۰۰): فرآیندهای میزبانی سرویس‌های آغاز شده.
  • سرویس پیش‌زمینه (امتیاز ۲۰۰): فرآیندهایی که میزبان سرویس‌های پیش‌زمینه هستند.
  • پیش‌زمینه (امتیاز ۰): برنامه‌ای که کاربر در حال حاضر با آن در تعامل است.

بررسی عمیق: تحریک PSI و LMKD

پی اس آی چیست؟

اطلاعات مربوط به توقف فشار (PSI) یک ویژگی هسته لینوکس است که روشی استاندارد برای اندازه‌گیری کمبود منابع ارائه می‌دهد. این ویژگی، زمان تأخیر وظایف به دلیل کمبود CPU، حافظه و I/O را ردیابی می‌کند.

PSI حافظه: «مقداری» در مقابل «کامل»

PSI حافظه به طور خاص تأخیرهای ناشی از کمبود حافظه (مثلاً انتظار برای بازیابی صفحه یا خطاها) را ردیابی می‌کند. این ابزار دو معیار ارائه می‌دهد:

  • some : درصد زمانی که حداقل یک وظیفه در حافظه متوقف شده است. این نشان می‌دهد که کمبود حافظه بر عملکرد تأثیر می‌گذارد اما برخی از کارها هنوز در حال انجام هستند.
  • full : درصد زمانی که طی آن تمام وظایف غیر بیکار به طور همزمان متوقف شده‌اند. این نشان دهنده یک وضعیت بحرانی است که در آن سیستم کاملاً مسدود شده و منتظر حافظه است.

چگونه PSI باعث LMKD می‌شود

دیمن فضای کاربری lmkd در هسته ثبت می‌شود تا در صورت تجاوز از آستانه‌های PSI (با نظارت بر /proc/pressure/memory ) اعلان‌هایی دریافت کند. هنگامی که سیستم فشار حافظه بالایی را تجربه می‌کند (مثلاً، توقف full که از مدت زمان پیکربندی شده تجاوز می‌کند)، هسته lmkd را بیدار می‌کند. lmkd سپس وضعیت سیستم را ارزیابی می‌کند و بر اساس امتیاز OOM و اندازه آنها، تصمیم می‌گیرد که آیا فرآیندها را از بین ببرد یا خیر، و کدام یک را.

تنظیم LMKD

رفتار LMKD را می‌توان با استفاده از ویژگی‌های سیستم تنظیم کرد.

پیدا کردن مقادیر تنظیم روی یک دستگاه

می‌توانید با اجرای دستور زیر، مقادیر تنظیم فعلی LMKD را در دستگاه متصل پیدا کنید:

adb shell getprop | grep lmk

خواص رایج LMKD

در اینجا برخی از ویژگی‌های کلیدی مورد استفاده برای تنظیم LMKD آورده شده است (برای لیست کامل به مستندات اندروید مراجعه کنید):

  • ro.lmk.use_psi : برای استفاده از مانیتورهای PSI برای تشخیص فشار حافظه، روی true تنظیم کنید (پیش‌فرض در اندروید ۱۰+).
  • ro.lmk.psi_partial_stall_ms : آستانه‌ی مدت زمان توقف (جزئی) بر some میلی‌ثانیه برای اجرای kill (به طور پیش‌فرض ۷۰ میلی‌ثانیه در دستگاه‌های معمولی، ۲۰۰ میلی‌ثانیه در دستگاه‌های با رم کم).
  • ro.lmk.psi_complete_stall_ms : آستانه‌ی مدت زمان توقف full (به میلی‌ثانیه) برای اجرای kill (پیش‌فرض ۷۰۰ میلی‌ثانیه).
  • ro.lmk.kill_heaviest_task : اگر true ، LMKD فرآیندی را که بیشترین حافظه را در بین کاندیداهای موجود در همان سطل OOM استفاده می‌کند، از بین می‌برد.

مقادیر تنظیم مربوطه در دستگاه تست (Google Pixel 8 Pro)

(توجه: پیش‌فرض‌های معمول برای دستگاه‌های رده بالا که اندروید ۱۵ را اجرا می‌کنند)

  • 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 به شدت بر سرعت پر شدن حافظه swap و فعال شدن LMKD kills تأثیر می‌گذارد. می‌توانید وضعیت ZRAM و swap را روی دستگاه با استفاده از این دستورات بررسی کنید:

# Check ZRAM sizing and usage
adb shell free -m

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

تمرین عملی: فعال‌سازی kswapd و lmkd

در این تمرین، شما از برنامه نمونه KswapdLmkdLab برای ایجاد فرآیندها در سطل‌های مختلف OOM استفاده خواهید کرد و سپس در فرآیند اصلی حافظه را برای فعال کردن kswapd و lmkd مصرف خواهید کرد.

این برنامه طوری پیکربندی شده است که به طور خودکار زیرفرآیندها را ایجاد کرده و حافظه را به آنها اختصاص دهد تا آنها را به اهداف جذابی برای LMKD تبدیل کند.

۱. ایجاد زیرفرآیندها

برنامه به طور خودکار زیرفرآیندهای زیر را هنگام اجرا ایجاد می‌کند:

  • فرآیند ذخیره شده (oom_score_adj >= 900)
  • فرآیند خدمات (oom_score_adj 500)
  • فرآیند خدمات پیش‌زمینه (oom_score_adj 200)

فرآیندها و امتیازات OOM آنها را با استفاده از ADB تأیید کنید:

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 : پیش‌زمینه (امتیاز OOM 0)
  • prcp : قابل درک (خدمات پیش‌زمینه، امتیاز OOM 200)
  • svc : سرویس شروع شده (امتیاز OOM 500)
  • cch : فرآیند ذخیره شده (امتیاز OOM 900)

۲. فشار حافظه را تحریک کنید

برنامه به طور خودکار شروع به تخصیص حافظه در فرآیند اصلی می‌کند. برای اینکه آزمایش در دستگاه‌های با رم بالا مؤثر باشد، برنامه همچنین به زیرفرآیندها دستور می‌دهد که حافظه (مثلاً ۵۰۰ مگابایت برای هر کدام) را تخصیص دهند تا آنها را به اهداف بهتری برای LMKD تبدیل کند.

نمونه برنامه در عمل

در اینجا تصویری از برنامه پس از اجرای آزمایشی روی گوگل پیکسل ۸ پرو (که تقریباً ۱۲ گیگابایت رم دارد) مشاهده می‌کنید.

نمونه اسکرین شات برنامه

تحلیل ردیابی پرفتو

برای ثبت این تعامل، از پیکربندی Perfetto زیر برای ثبت زمان‌بندی، شمارنده‌های حافظه، توقف‌های LMK و اطلاعات مربوط به واماندگی فشار (PSI) استفاده کنید.

پیکربندی کامل

با اجرای Perfetto به همراه زمان‌بندی، شمارنده‌های حافظه، حذف LMK و اطلاعات مربوط به واماندگی فشار (PSI)، تعامل را ثبت کنید:

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

می‌توانید ببینید که MemFree از قبل نسبتاً پایین است و تحت فشار مداوم قرار دارد. kswapd دائماً در حال کار است و با حذف صفحات mem.rss.file و انتقال mem.rss.anon به mem.swap از تمام فرآیندهای kswapdlmkdlab (فرآیند اصلی و زیرفرآیندها) و احتمالاً از فرآیندهای دیگری که در این تصویر نشان داده نشده‌اند، فشار را کاهش می‌دهد. در عین حال، برنامه kswapdlmkdlab به تخصیص حافظه ادامه می‌دهد و فشار را سریع‌تر از آنچه kswapd می‌تواند بازیابی کند، افزایش می‌دهد.

وقتی فشار خیلی بالا می‌رود، همانطور که در psi.mem دیده می‌شود که برای مدت زمان کافی بالا بوده است، lmkd بیدار می‌شود و برخی از فرآیندها را از بین می‌برد. می‌توانید ببینید که lmkd به امتیازات OOM احترام می‌گذارد و ابتدا kswapdlmkdlab:cached ، سپس :service و در نهایت :foreground از بین می‌برد.

جدول زمانی وقایع را مرور کنید و موارد زیر را در نظر بگیرید:

  • چگونه kswapd و lmkd مکمل یکدیگر هستند: kswapd اولین کسی است که به فشار حافظه پاسخ می‌دهد، اما lmkd زمانی کمک می‌کند که پهنای باند بازیابی شده توسط kswapd پاسخگوی تقاضای تخصیص نباشد.
  • نرخ آزادسازی حافظه: زمان صرف شده توسط CPU در kswapd و میزان حافظه‌ای که با حذف mem.rss.file یا تعویض mem.rss.anon به mem.swap آزاد می‌شود را مشاهده کنید. این را با دوره‌های کوتاه فعالیت در lmkd مقایسه کنید که منجر به آزادسازی مقادیر زیادی از حافظه خصوصی فرآیند می‌شود.

پرس‌وجوها

این کوئری‌ها را در رابط کاربری Perfetto (Query SQL) اجرا کنید تا داده‌ها را از ردپای خود استخراج کنید.

۱. فعالیت kswapd

برای پیدا کردن اینکه چه زمانی سرویس swap هسته فعال و در حال اجرا بوده است، دستور زیر را اجرا کنید:

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

خروجی نمونه:

تی اس دور ایالت
۳۰۳۱۷۶۳۳۰۵۲۹۶۹ ۱۵۹۱۸۰ دویدن
۳۰۳۱۷۶۳۳۳۹۸۳۴۷ ۳۹۹۹۱۸۶ دویدن
۳۰۳۱۷۶۳۸۴۴۸۱۱۱ ۱۸۴۷۹۴۱ دویدن
۳۰۳۱۷۶۴۱۴۵۵۳۵۴ ۱۰۳۱۰۰۶ دویدن
۳۰۳۱۷۶۴۳۲۷۲۶۱۵ ۸۸۸۳۸۷ دویدن

۲. LMKD می‌کشد

LMKD عملیات kill با حافظه کم را در جدول instant می‌نویسد. برای پرس و جو از تمام kill های LMKD:

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 (فضای swap در ZRAM بسیار کم است و thrashing رخ داده است)
    • 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 : حداکثر درصد حذف صفحه در زمان kill.

خروجی نمونه:

تی اس نام
۳۰۳۲۶۱۴۸۶۷۹۹۶۷ lmk، ۲۳۰۸،۳،۹۰۰،۲۰۱،۰
۳۰۳۳۰۴۳۹۷۶۳۷۱۰ lmk، ۲۳۰۹، ۳، ۵۰۰، ۲۰۱، ۰
۳۰۳۳۴۹۸۵۹۹۹۸۳۷ lmk، ۲۳۱۰، ۲، ۲۰۰، ۰، ۳۰۷

تجسم

برای تجسم داده‌ها، می‌توانید از اسکریپت gnuplot زیر برای رسم نمودار حافظه آزاد سیستم، فعالیت kswapd، kills lmkd و PSI در یک سری زمانی واحد استفاده کنید. این اسکریپت فرض می‌کند که از دایرکتوری build top اندروید اجرا می‌شود.

نمودار خروجی نمونه

نمودار زیر با استفاده از اسکریپت بالا و با داده‌های نمونه‌ای که نشان‌دهنده‌ی اجرای آزمایشی هستند، ایجاد شده است.

نمودار فشار حافظه

توضیح طرح داستان:

این نمودار، تعامل پویا بین اجزای مختلف مدیریت حافظه را در طول تست استرس نشان می‌دهد:

  1. کاهش حافظه آزاد : همزمان با اختصاص حافظه توسط برنامه اصلی، حافظه آزاد سیستم (خط بنفش) به طور پیوسته کاهش می‌یابد.
  2. فعال‌سازی kswapd : وقتی حافظه آزاد از مقدار مشخصی کمتر می‌شود، kswapd با ارسال پالس‌های آبی رنگ (یا: ضربه‌های آبی رنگ) بیدار می‌شود تا با جابجایی به ZRAM، حافظه را بازیابی کند. این اتفاق به صورت افزایش ناگهانی و متناوب حافظه قابل مشاهده است.
  3. افزایش ناگهانی PSI : همزمان با اینکه kswapd برای همگام شدن با نرخ بالای تخصیص حافظه تلاش می‌کند، رشته‌ها (threads) در تخصیص حافظه دچار مشکل می‌شوند و باعث افزایش ناگهانی PSI (اطلاعات توقف فشار) (خط سبز) می‌شوند.
  4. LMKD Kills : وقتی PSI به سطوح بحرانی می‌رسد (مثلاً از آستانه ro.lmk.psi_complete_stall_ms به صورت مفهومی فراتر می‌رود) و حافظه آزاد بسیار کم است، lmkd با از بین بردن فرآیندهای با اولویت پایین (پیام‌های نارنجی در زمان‌های 30 و 45) مداخله می‌کند تا بخش‌های بزرگی از حافظه را آزاد کند. توجه داشته باشید که بلافاصله پس از kill، حافظه آزاد افزایش و PSI کاهش می‌یابد که نشان‌دهنده اثربخشی kill در کاهش فشار است. ________________________________________________________________________________

← بازیابی حافظه: حذف و تعویض | ↑ بالا