تتناول هذه الصفحة التفاعل بين kswapd وlmkd على Android،
وتوضّح كيفية عملهما معًا لإدارة الضغط على الذاكرة.
خلفية
يستخدم Android آليتَين أساسيتَين لاستعادة الذاكرة عندما ينخفض مستوى النظام:
kswapd: هو برنامج خلفية عادي لنواة Linux يستعيد الصفحات من خلال إزالة الصفحات النظيفة المستندة إلى الملفات أو تبديل الصفحات المجهولة إلى ZRAM.lmkd: برنامج Low Memory Killer daemon في مساحة المستخدم في Android. عندما لا يتمكّنkswapdمن مواكبة متطلبات الذاكرة ويزداد الضغط على النظام (كما يشير PSI)، يتدخّلlmkdلإنهاء العمليات من أجل إخلاء أجزاء أكبر من الذاكرة.
kswapd وlmkd هما نظامان متكاملان لاستعادة الذاكرة. وتعمل على تحقيق الهدف نفسه (توفير مساحة في الذاكرة) ولكن بطرق مختلفة. للمقارنة
والتباين:
- الاسترداد مقابل التدمير: يتجاهل
kswapdصفحات الذاكرة التي يمكن قراءتها من وحدة التخزين، أو ينقل صفحات الذاكرة إلى أقسام ذاكرة أخرى أو وحدة تخزين يمكن قراءتها عند الطلب. يؤديlmkdإلى إنهاء العمليات، ما يؤدي إلى تدمير الحالة غير المتغيّرة. - معدل نقل البيانات المسترد: يستهلك
kswapdقدرًا أكبر من وحدة المعالجة المركزية (CPU) لاسترداد مقدار معيّن من الذاكرة الخالية مقارنةً بـlmkd، ويستغرق وقتًا أطول لاسترداد هذه الذاكرة. يمكن لـlmkdاستعادة كميات كبيرة من الذاكرة في فترات قصيرة وبجهد قليل نسبيًا. يُرجى العِلم أنّ جهد وحدة المعالجة المركزية على الأجهزة الجوّالة لا يؤدي إلى زيادة وقت الاستجابة فحسب، بل يؤدي أيضًا إلى استهلاك طاقة البطارية.
مجموعات نتائج نفاد الذاكرة (OOM)
يخصّص نظام Android تعديلاً لنتيجة نفاد الذاكرة (OOM) (oom_score_adj) للعمليات استنادًا إلى أهميتها بالنسبة إلى المستخدم. يتم إنهاء العمليات التي حصلت على نتائج أعلى أولاً.
تشمل المجموعات الشائعة ما يلي:
- العمليات المخزَّنة مؤقتًا (النتيجة >= 900): هي العمليات غير المطلوبة حاليًا، ويتم الاحتفاظ بها لإعادة تشغيلها بشكل أسرع.
- الخدمة (النتيجة 500): تعالج الخدمات التي بدأت الاستضافة.
- خدمة تعمل في المقدّمة (النتيجة 200): العمليات التي تستضيف خدمات تعمل في المقدّمة.
- في المقدّمة (النتيجة 0): التطبيق الذي يتفاعل معه المستخدم حاليًا.
نظرة متعمّقة: PSI وLMKD
ما هي PSI؟
معلومات توقُّف الضغط (PSI) هي ميزة في نواة Linux توفّر طريقة أساسية لقياس النقص في الموارد. ويتتبّع الوقت الذي تتأخر فيه المهام بسبب نقص في وحدة المعالجة المركزية (CPU) والذاكرة والإدخال/الإخراج.
مؤشر PSI للذاكرة: "بعض" مقابل "كامل"
يتتبّع مؤشر PSI للذاكرة على وجه التحديد حالات التأخير الناتجة عن نقص الذاكرة (مثل الانتظار لاستعادة الصفحة أو إعادة حدوث الأخطاء). ويوفّر مقياسَين:
some: النسبة المئوية للوقت الذي توقفت فيه مهمة واحدة على الأقل بسبب الذاكرة يشير ذلك إلى أنّ نقص الذاكرة يؤثر في الأداء، ولكن بعض العمل لا يزال قيد التقدّم.full: النسبة المئوية للوقت الذي توقفت فيه جميع المهام غير الخاملة في الوقت نفسه. يشير هذا إلى حالة حرجة حيث يتم حظر النظام تمامًا في انتظار الذاكرة.
كيفية تفعيل PSI لـ LMKD
يسجّل برنامج lmkd daemon في مساحة المستخدم في النواة لتلقّي الإشعارات
عند تجاوز حدود PSI (من خلال مراقبة /proc/pressure/memory). عندما
يواجه النظام عبئًا كبيرًا على الذاكرة (على سبيل المثال، تجاوز توقُّف full
المدة التي تم ضبطها)، تنشّط النواة lmkd. بعد ذلك، يقيّم lmkd حالة النظام ويقرّر ما إذا كان سيتم إنهاء العمليات، ويحدّد العمليات التي سيتم إنهاؤها، استنادًا إلى نتائج نفاد الذاكرة (OOM) وحجمها.
ضبط LMKD
يمكن ضبط سلوك LMKD باستخدام خصائص النظام.
العثور على قيم الضبط على جهاز
يمكنك العثور على قيم ضبط LMKD الحالية على جهاز متصل من خلال تشغيل:
adb shell getprop | grep lmk
خصائص LMKD الشائعة
في ما يلي بعض السمات الرئيسية المستخدَمة لضبط LMKD (يُرجى الرجوع إلى مستندات Android للاطّلاع على القائمة الكاملة):
ro.lmk.use_psi: يتم ضبطه علىtrueلاستخدام أدوات مراقبة PSI لرصد الضغط على الذاكرة (الإعداد التلقائي في الإصدار 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، ينهي برنامج LMKD العملية التي تستخدم أكبر قدر من الذاكرة من بين العمليات المرشحة في مجموعة نفاد الذاكرة (OOM) نفسها.
قيم الضبط ذات الصلة على جهاز الاختبار (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 بشكل كبير في سرعة امتلاء مساحة التخزين المؤقتة وبدء عمليات إنهاء التطبيقات من خلال LMKD. يمكنك التحقّق من حالة ZRAM والمساحة الاحتياطية على الجهاز باستخدام الأوامر التالية:
# 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.
1. إنشاء عمليات فرعية
ينشئ التطبيق تلقائيًا العمليات الفرعية التالية عند تشغيله:
- العمليات المخزَّنة مؤقتًا (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: في المقدّمة (نتيجة نفاد الذاكرة 0) -
prcp: تطبيق يمكن ملاحظته (خدمة تعمل في المقدّمة، نتيجة نفاد الذاكرة 200) -
svc: تم بدء الخدمة (نتيجة نفاد الذاكرة 500) cch: عملية مخزَّنة مؤقتًا (نتيجة نفاد الذاكرة 900)
2. تفعيل الضغط على الذاكرة
سيبدأ التطبيق تلقائيًا في تخصيص الذاكرة في العملية الرئيسية. لجعل الاختبار فعّالاً على الأجهزة ذات ذاكرة الوصول العشوائي الكبيرة، يطلب التطبيق أيضًا من العمليات الفرعية تخصيص الذاكرة (مثلاً، 500 ميغابايت لكل منها) لجعلها أهدافًا أفضل لـ LMKD.
مراقبة إيقاف العملية الفرعية نهائيًا
يراقب التطبيق توقُّف هذه العمليات الفرعية باستخدام آلية IBinder.linkToDeath:
- ترتبط العملية الرئيسية بخدمة في العملية المستهدَفة باستخدام
bindService. - عند الاتصال، يحصل على عنصر
IBinderالذي يمثّل الخدمة. - يتم تسجيل تنفيذ
IBinder.DeathRecipientمن خلال استدعاءlinkToDeathفي أداة الربط. - عند توقّف العملية المستهدَفة (على سبيل المثال، عند إنهائها من خلال LMKD)، يستدعي النظام
الطريقة
binderDied()، ما يسمح للتطبيق بتسجيل حدث التوقّف بشكل غير متزامن.
لمنع هذا الربط من رفع أولوية العمليات المستهدَفة (ما قد يؤدي إلى إحباط الغرض من التمرين)، يستخدم التطبيق العلامة Context.BIND_WAIVE_PRIORITY.
نموذج تطبيق قيد التشغيل
في ما يلي لقطة شاشة للتطبيق بعد اكتمال عملية اختبار على هاتف Google Pixel 8 Pro (الذي تبلغ سعة ذاكرة الوصول العشوائي الإجمالية فيه 12 غيغابايت تقريبًا).
تحليل تتبُّع Perfetto
لتسجيل التفاعل، استخدِم إعدادات Perfetto التالية لتسجيل الجدولة وعدادات الذاكرة وعمليات إنهاء LMK ومعلومات توقُّف الضغط (PSI).
إعدادات Perfetto
سجِّل التفاعل من خلال تشغيل 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 (الأقل قابلية للإنهاء).
يمكنك ملاحظة أنّ MemFree منخفضة إلى حدّ ما وتتعرّض لضغط مستمر.
يعمل kswapd باستمرار ويخفّف الضغط من خلال إسقاط صفحات mem.rss.file
ونقل mem.rss.anon إلى mem.swap من جميع عمليات kswapdlmkdlab
(العملية الرئيسية والعمليات الفرعية)، ومن المحتمل من عمليات أخرى
غير معروضة في لقطة الشاشة هذه. في الوقت نفسه، يستمر تطبيق kswapdlmkdlab
في تخصيص الذاكرة، ما يزيد من الضغط بشكل أسرع من قدرة kswapd على
استعادة الذاكرة.
عندما يصبح الضغط مرتفعًا جدًا، كما يظهر في ارتفاع psi.mem لفترة زمنية كافية، يتم تنشيط lmkd وإنهاء بعض العمليات. يمكنك ملاحظة أنّ lmkd يراعي نتائج نفاد الذاكرة، فينهي kswapdlmkdlab:cached أولاً، ثم :service، ثم :foreground.
راجِع المخطط الزمني للأحداث وفكِّر في ما يلي:
- كيفية تكامل
kswapdوlmkdمع بعضهما:kswapdهو أول من يستجيب لضغط الذاكرة، ولكنlmkdيساعد عندما لا يفي النطاق الترددي للاسترداد فيkswapdبطلب التخصيص. - معدّل إخلاء الذاكرة: يمكنك الاطّلاع على وقت وحدة المعالجة المركزية المستغرَق في
kswapdوالذاكرة التي تتم استعادتها من خلال إزالةmem.rss.fileأو تبديلmem.rss.anonإلىmem.swap. قارِن ذلك بالنشاط القصير والمكثّف فيlmkdالذي يؤدي إلى إخلاء مساحة كبيرة من الذاكرة الخاصة بالعمليات.
طلبات البحث
يمكنك تنفيذ طلبات البحث هذه في واجهة مستخدم Perfetto (طلب بحث SQL) لاستخراج البيانات من التتبُّع.
1. نشاط kswapd
لمعرفة متى كان برنامج swap daemon في النواة نشطًا وقيد التشغيل، نفِّذ ما يلي:
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. عمليات الإغلاق بسبب نقص الذاكرة (LMKD)
يكتب برنامج LMKD عمليات الإغلاق بسبب نقص الذاكرة في جدول instant. للاستعلام عن جميع عمليات إنهاء 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_KILL1:NOT_RESPONDING2:LOW_SWAP_AND_THRASHING(مساحة إبدال ZRAM منخفضة للغاية وحدثت مشكلة في الذاكرة)-
3:LOW_MEM_AND_SWAP(مساحة الذاكرة الخالية ومساحة تبديل ZRAM في النظام منخفضة) 4:LOW_MEM_AND_THRASHING5:DIRECT_RECL_AND_THRASHING6:LOW_MEM_AND_SWAP_UTIL7:LOW_FILECACHE_AFTER_THRASHING8:LOW_MEM9: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 ومؤشر PSI في سلسلة زمنية واحدة. يفترض النص البرمجي أنّه يتم تشغيله من الدليل العلوي لإصدار Android.
مثال على رسم بياني للناتج
تم إنشاء المخطط التالي باستخدام النص البرمجي السابق مع عيّنات بيانات تمثّل عملية الاختبار.
شرح الحبكة:
يوضّح هذا المخطط التفاعل الديناميكي بين مكوّنات إدارة الذاكرة المختلفة أثناء اختبار الإجهاد:
- انخفاض الذاكرة الفارغة: عندما يخصّص التطبيق الرئيسي الذاكرة، تنخفض الذاكرة الفارغة في النظام (الخط الأرجواني) بشكل ثابت.
- تفعيل kswapd: عندما تنخفض الذاكرة الخالية عن علامات مائية معيّنة،
يتم تنشيط
kswapd(النبضات الزرقاء) لاستعادة الذاكرة من خلال التبديل إلى ZRAM. ويظهر ذلك على شكل ارتفاعات متقطّعة. - ارتفاعات PSI: بينما يحاول
kswapdمواكبة المعدل المرتفع للتخصيص، تبدأ سلاسل المحادثات في التوقف عند تخصيص الذاكرة، مما يتسبب في ارتفاع PSI (معلومات توقف الضغط) (الخط الأخضر). - عمليات الإنهاء التي ينفّذها برنامج LMKD: عندما يصل مؤشر PSI إلى مستويات حرجة (على سبيل المثال، تجاوز الحدّ الأقصى لمؤشر
ro.lmk.psi_complete_stall_msمن الناحية النظرية) وتكون الذاكرة الخالية منخفضة للغاية، يتدخّل برنامجlmkdمن خلال إنهاء العمليات ذات الأولوية المنخفضة (النبضات البرتقالية في الوقت 30 و45) لإخلاء أجزاء كبيرة من الذاكرة. يُرجى ملاحظة أنّه بعد إنهاء العملية مباشرةً، تزداد الذاكرة الخالية وينخفض مؤشر PSI، ما يوضّح فعالية إنهاء العملية في تخفيف الضغط. ________________________________________________________________________________
← استعادة الذاكرة: الإخلاء ومساحة الإبدال | ↑ للأعلى | إعادة صفحات الذاكرة إلى نظام التشغيل →