تتناول هذه الصفحة التفاعل بين kswapd وlmkd على Android،
وتوضّح كيفية عملهما معًا لإدارة الضغط على الذاكرة.
خلفية
يستخدم Android آليتَين أساسيتَين لاستعادة الذاكرة عندما تنخفض مساحة النظام:
kswapd: هو برنامج خلفية عادي في نواة Linux يستعيد الصفحات من خلال إزالة الصفحات النظيفة المستندة إلى الملفات أو تبديل الصفحات المجهولة إلى ZRAM.lmkd: برنامج 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 kernel توفّر طريقة أساسية لقياس النقص في الموارد. وتتتبّع الوقت الذي تتأخر فيه المهام بسبب نقص في وحدة المعالجة المركزية (CPU) والذاكرة والإدخال/الإخراج.
مؤشر 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 (يُرجى الرجوع إلى مستندات 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)
تحقَّق من العمليات ونتائج نفاد الذاكرة باستخدام 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
لمعرفة متى كان برنامج 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، ما يوضّح فعالية إنهاء العملية في تخفيف الضغط. ________________________________________________________________________________
← استعادة الذاكرة: الإخلاء والإبدال | ↑ للأعلى | إعادة صفحات الذاكرة إلى نظام التشغيل →