لا تعمل عمليات التطبيقات على Android بشكل منفصل. تعتمد التطبيقات غالبًا على الخدمات التي توفّرها تطبيقات أخرى أو النظام نفسه. عندما تتصل إحدى العمليات بعملية أخرى من خلال ربط خدمة، يتم إنشاء تبعية تؤثر بشكل كبير في طريقة إدارة إطار عمل Android للذاكرة.
حالات العمليات ونتائج OOM
يستخدم إطار عمل Android حالات العمليات لتتبُّع أهمية كل عملية قيد التشغيل. تستخدم OomAdjuster هذه الحالات بعد ذلك لتعيين قيمة تعديل نقاط OOM (oom_score_adj) تتراوح بين -1000 و1000.
يشير انخفاض قيمة oom_score_adj إلى أنّ العملية أكثر أهمية وأقل عرضة لأن يتم إيقافها من خلال أداة Low Memory Killer (LMK).
حالات المعالجة الشائعة
يعرض الجدول التالي بعض حالات العمليات الأكثر شيوعًا وقيم oom_score_adj النموذجية الخاصة بها. للحصول على قائمة كاملة وحديثة، يُرجى الرجوع إلى android.app.ActivityManager وcom.android.server.am.psc.Constants في رمز المصدر لنظام Android.
| حالة المعالجة (اختصار) | الوصف | oom_score_adj العادي |
|---|---|---|
| PER (ثابتة) | عمليات النظام التي يجب تشغيلها دائمًا (مثل الاتصال الهاتفي) | -800 |
| أبرز | العملية التي يتفاعل معها المستخدم حاليًا | 0 |
| VIS (مرئي) | تتضمّن العملية نشاطًا مرئيًا (على سبيل المثال، خلف مربّع حوار شفاف). | 100 |
| PERC (مدرَك) | عملية في الخلفية يكون المستخدم على دراية بها (مثل تشغيل الموسيقى) | 200 |
| FGS | عملية استضافة خدمة تعمل في المقدّمة | من 0 إلى 200 (يختلف) |
| BTOP (الحدّ الأعلى) | عملية مرتبطة بتطبيق TOP | 100 |
| BFGS | خدمة تعمل في المقدّمة ومرتبطة (عادةً ما تكون مرتبطة بالنظام) | 0 |
| السابق (Previous) | آخر عملية كان المستخدم فيها قبل العملية الحالية | 700 |
| مخزَّن مؤقتًا | التطبيقات التي تعمل في الخلفية ويمكن إيقافها بأمان | من 900 إلى 999 |
تأثير عمليات ربط الخدمات
عندما يرتبط أحد عمليات العميل (مثل تطبيق في الحالة TOP) بخدمة في عملية خادم، غالبًا ما تكتسب عملية الخادم أولوية أعلى. ويضمن ذلك بقاء الخدمة متاحة طالما يحتاج إليها العميل.

التحكّم في الاكتساب باستخدام علامات BIND
يكون التوريث هو السلوك التلقائي عند استخدام Context.BIND_AUTO_CREATE.
ومع ذلك، يمكن للمطوّرين التحكّم في كيفية تأثير الربط في أهمية العملية المستهدَفة باستخدام علامات مختلفة في bindService().
علامات BIND الرئيسية لنتيجة OOM
تكون العلامات التالية أكثر صلةً عند إدارة ضغط الذاكرة على مستوى النظام:
-
BIND_AUTO_CREATE: هذا هو الإبلاغ الأكثر شيوعًا. ويضمن بدء عملية الخدمة واستمرارها طالما أنّ الربط متوفّر. ويؤدي ذلك تلقائيًا إلى رفع أولوية عملية الخادم لتتطابق مع أولوية العميل. BIND_NOT_FOREGROUND: يمنع رفع أولوية الجدولة (أولوية وحدة المعالجة المركزية) لعملية الخدمة المستهدَفة إلى المقدّمة. ومع ذلك، يظل بإمكانك رفع أولوية الذاكرة (oom_score_adj). ويكون ذلك مفيدًا لتنفيذ مهام في الخلفية لا تتنافس مع واجهة المستخدم على دورات وحدة المعالجة المركزية، ولكن يجب أن تظل محمية من الإيقاف.BIND_WAIVE_PRIORITY: علامة قوية جدًا توجّه النظام إلى عدم التأثير في أولوية الجدولة أو إدارة الذاكرة للعملية المستهدَفة. ستتم إدارة عملية الخدمة كما لو كانت عملية عادية تعمل في الخلفية ضمن قائمة العناصر الأقل استخدامًا، ما يجعلها مؤهَّلة لإيقافها بسبب خطأ نفاد الذاكرة حتى أثناء ربطها.-
BIND_ABOVE_CLIENT: يشير إلى أنّ الخدمة أكثر أهمية من تطبيق العميل نفسه. عندما يحتاج النظام إلى استعادة الذاكرة، سيُفضّل إيقاف تطبيق العميل قبل إيقاف الخدمة المرتبطة. هذا النوع "أقوى" منBIND_AUTO_CREATEلأنّه يوفّر طبقة حماية إضافية للخدمة على حساب العميل. BIND_NOT_PERCEPTIBLE: يخفّض مستوى أهمية الخدمة المستهدَفة إلى ما دون مستوىPERCEPTIBLE، ما يتيح للنظام استعادة الذاكرة لإتاحة مساحة لعمليات أكثر أهمية يلاحظها المستخدم.
تجربة عملية: مراقبة تأثيرات الربط
سنستخدم تطبيق MemoryLab لتوضيح كيف يؤثّر ربط من تطبيق TOP في حالة عملية منفصلة.
1. تشغيل MemoryLab
يؤدي الأمر التالي إلى تشغيل التطبيق. بعد فتحه، تأكَّد من بقاء التطبيق في المقدّمة (لا تضغط على "الصفحة الرئيسية" أو تبدّل التطبيقات بعد).
adb shell am start -n com.android.memorylab/.MainActivity
2. تحديد العمليات
تحقَّق من حالات العملية قبل الربط. يشغّل تطبيق MemoryLab واجهة المستخدم الرئيسية في عملية واحدة، ويتضمّن RemoteService يتم تشغيله في عملية :remote.
adb shell dumpsys activity processes com.android.memorylab
مثال على مقتطف الناتج:
Process OOM control (154 total, non-act at 7, non-svc at 7):
Proc #0: fg T/A/TOP LCMNFUATI t: 0 13470:com.android.memorylab/u0a417 (top-activity)
oom: max=1001 curRaw=0 setRaw=0 cur=0 set=0
state: cur=TOP set=TOP lastRss=0.00 lastCachedRss=0.00
ستظهر العملية الرئيسية com.android.memorylab في الحالة TOP. لم تبدأ عملية
:remote بعد.
3- ربط مشغّل
أرسِل بثًا إلى التطبيق لتفعيل ربط الخدمة:
adb shell am broadcast -a com.android.memorylab.LEAK_BINDER
4. مراقبة الحالة المرتفعة
تحقَّق من حالات العملية مرة أخرى:
adb shell dumpsys activity processes | grep -A 10 "com.android.memorylab"
مثال على مقتطف الناتج:
Proc # 1: vis F/ /BTOP ---NFUATI t: 0 13560:com.android.memorylab:remote/u0a417 (service)
com.android.memorylab/.RemoteService<=Proc{13470:com.android.memorylab/u0a417}
oom: max=1001 curRaw=100 setRaw=100 cur=100 set=100
state: cur=BTOP set=BTOP lastRss=0.00 lastCachedRss=0.00
تعمل العملية :remote الآن وهي في حالة BTOP (أعلى موضع مرتبط) مع oom_score_adj بقيمة 100. وهي أكثر حماية بكثير من خدمة تُشغَّل في الخلفية عادية (والتي تكون في المستوى 500 أو أعلى). توضّح الرمز
<=Proc{...} العملية المسؤولة عن رفع مستوى الأولوية هذا.
5. التشغيل في الخلفية
اضغط على زر HOME على الجهاز. يُرجى التحقّق من الحالات مرة أخرى:
adb shell dumpsys activity processes | grep -A 10 "com.android.memorylab"
مثال على مقتطف الناتج:
Proc # 2: prev b/ /LAST --------I t: 0 13560:com.android.memorylab:remote/u0a417 (service)
com.android.memorylab/.RemoteService<=Proc{13470:com.android.memorylab/u0a417}
oom: max=1001 curRaw=700 setRaw=700 cur=700 set=700
state: cur=LAST set=LAST lastRss=0.00 lastCachedRss=0.00
Proc # 1: prev b/ /LAST --------I t: 0 13470:com.android.memorylab/u0a417 (previous)
oom: max=1001 curRaw=700 setRaw=700 cur=700 set=700
state: cur=LAST set=LAST lastRss=209MB lastCachedRss=0.00
الآن، انتقلت كلتا العمليتين إلى حالة أولوية أقل (PREV /
oom_score_adj 700)، لأنّ عملية العميل لم تعُد TOP. (ملاحظة:
يشير LAST في تفريغ الحالة إلى الحالة الداخلية LAST_ACTIVITY، والتي
تتطابق مع PREV في الملخّصات العالية المستوى).
التحليل باستخدام procstats
تقدّم أداة procstats عرضًا تاريخيًا لهذه الحالات.
# View stats for MemoryLab over the last hour
adb shell dumpsys procstats --hours 1 com.android.memorylab
مثال على مقتطف الناتج:
* com.android.memorylab / u0a417 / v37:
* Prc com.android.memorylab / u0a417 / v37:
TOTAL: 0.89% (0.00-0.00-0.00/0.00-0.00-0.00/210MB-210MB-210MB over 1)
Top: 0.89% (0.00-0.00-0.00/0.00-0.00-0.00/210MB-210MB-210MB over 1)
* Prc com.android.memorylab:remote / u0a417 / v37:
TOTAL: 0.19%
Bnd Top: 0.19%
يشير Bnd Top هنا إلى النسبة المئوية للوقت الذي استغرقه التطبيق في ربط العملية البعيدة في الحالة TOP.
تسجيل عمليات الربط وتحليلها باستخدام Perfetto
في حين يقدّم لك dumpsys لقطة سريعة، يتيح لك Perfetto الاطّلاع على اللحظة المحدّدة التي يحدث فيها الربط وكيف يتغيّر تقييم OOM في الوقت الفعلي.
1. تسجيل عملية تتبُّع
استخدِم إعدادًا يتضمّن linux.process_stats وفئة am atrace:
adb shell perfetto -c - --txt -o /data/misc/perfetto-traces/service_bindings.perfetto-trace <<EOF
buffers: { size_kb: 65536 }
data_sources: {
config {
name: "linux.process_stats"
process_stats_config { proc_stats_poll_ms: 100 }
}
}
data_sources: {
config {
name: "linux.ftrace"
ftrace_config { ftrace_events: "am/am_proc_bound" }
}
}
duration_ms: 15000
EOF
2. عمليات نقل نتائج أخطاء نفاد الذاكرة لطلبات البحث
باستخدام PerfettoSQL، يمكنك الاطّلاع على كيفية تغيُّر نتيجة OOM للعملية البعيدة مقارنةً بعملية واجهة المستخدم:
SELECT ts, p.name, value AS oom_score_adj
FROM counter c
JOIN process_counter_track t ON c.track_id = t.id
JOIN process p USING (upid)
WHERE p.name LIKE 'com.android.memorylab%'
AND t.name = 'oom_score_adj'
ORDER BY ts;
3- تحديد أحداث الربط
لمعرفة الوقت الذي تم فيه إنشاء تبعية ربط والعملية التي بدأت فيها، استخدِم طلب البحث التالي:
SELECT
s.ts,
p.name AS process_name,
t.name AS thread_name,
s.name AS slice_name
FROM slice s
JOIN thread_track tt ON s.track_id = tt.id
JOIN thread t USING (utid)
JOIN process p USING (upid)
WHERE s.name LIKE 'bindService:{com.android.memorylab%';
عمليات الربط بين النظام والتطبيق
يرتبط نظام التشغيل Android نفسه غالبًا بالخدمات في التطبيقات التابعة لجهات خارجية لتوفير الوظائف الأساسية. وغالبًا ما يكون الهدف من عمليات الربط هذه هو تقليل وقت الاستجابة. من خلال إبقاء إحدى العمليات نشطة وفي الذاكرة، يتجنّب النظام النفقات العامة الباهظة الثمن لـ "تشغيل على البارد" (تحميل حزمة APK، وتهيئة وقت التشغيل، وإنشاء كائن التطبيق) عند حدوث تفاعل المستخدم المهم. تتوفّر روابط أخرى لمنع عمليات البدء البارد المتكرّرة للتطبيقات التي تحتاج إلى معالجة تدفقات أحداث في الخلفية.
في ما يلي بعض الأمثلة الواقعية التي يمكنك ملاحظتها على جهاز عادي:
VoiceInteractor
يتوقّع المستخدمون أن يكون المساعد الرقمي مضمّنًا في نظام تشغيل هواتفهم، وأن يتمكّنوا من استدعائه على الفور باستخدام كلمة تنشيط منطوقة أو إيماءة إدخال سريعة، وأن يكون التفاعل سلسًا وبدون أي عوائق.
عندما يتم تفعيل مشغِّل المساعد (مثل الكلمة المفتاح "OK Google" على هواتف Google Pixel)، يجب أن يستجيب المساعد الرقمي على الفور. لضمان ذلك، يحتفظ system_server بربط دائم بخدمة التفاعل الصوتي التي يختارها المستخدم.

إذا تحققت من حالات العملية (على سبيل المثال، باستخدام dumpsys activity processes)، قد تظهر لك عملية مثل com.google.android.googlequicksearchbox:interactor في الحالة BFGS (خدمة مرتبطة تعمل في المقدّمة)، ويتم إبقاؤها نشطة من خلال ربط من system_server (معرّف المستخدم 1000).
NotificationListenerService
في بعض عمليات الربط بين النظام والتطبيق، لا يكون الهدف هو تقليل وقت الاستجابة، بل منع عمليات البدء البارد المتكررة.
NotificationListenerService،
وهي خدمة تتلقّى مكالمات من النظام عند نشر إشعارات جديدة
أو إزالتها، وهي مثال رئيسي على ذلك. قد يتلقّى مستخدم الهاتف الذكي العادي مئات الإشعارات على مدار اليوم. إذا ألغى النظام ربط تطبيق بخدمة الاستماع إلى الإشعارات، من المرجّح أن تنتقل عملية هذا التطبيق إلى حالة التخزين المؤقت وقد يوقفها LMK.
وعند وصول الإشعار التالي، ربما بعد ثوانٍ، سيضطر النظام إلى إعادة تشغيل عملية التطبيق بالكامل من البداية لتسليم الحدث. وستؤدي دورة الإيقاف والتشغيل البارد المستمرة هذه إلى استهلاك وحدة المعالجة المركزية والبطارية بشكل أكبر بكثير من مجرد إبقاء العملية مرتبطة ونشطة في الخلفية.
"الشاشة -1" (خلاصة الأخبار) في مشغّل التطبيقات
تجمع تطبيقات Launcher الحديثة عادةً بين وظيفة التنقّل الأساسية (رموز الشاشة الرئيسية والأدوات) وخلاصة الأخبار المتوفّرة على إحدى شاشات Launcher والمدمجة بسلاسة مع تجربة المستخدم في Launcher. قد توفّر تطبيقًا آخر خلاصة الأخبار. على سبيل المثال، يدمج مشغّل التطبيقات على هاتف Google Pixel خلاصة توفّرها تطبيق Google.
عند التمرير سريعًا لليسار على الشاشة الرئيسية لعرض خلاصة الأخبار، يجب أن يكون الانتقال سلسًا. يحقّق المشغّل ذلك من خلال الربط بواجهة خدمة في التطبيق الذي يوفّر خلاصة الأخبار، والحفاظ على هذا الربط نشطًا طالما أنّ المشغّل نشط. يؤدي ذلك إلى إبقاء محتوى الخلاصة معروضًا وجاهزًا في الذاكرة حتى عندما لا تنظر إليه.
أمثلة شائعة أخرى
- مشغّل التطبيقات (HOME_APP_ADJ): يحتوي تطبيق مشغّل التطبيقات (Home) على خانة خاصة به في قائمة الأولوية. على الرغم من أنّها لا تكون مرتبطة دائمًا بخدمة، يتم تعيينها بالرمز
HOME_APP_ADJ(عادةً 600). يفضّل النظام إبقاء مشغّل التطبيقات نشطًا لأنّ المستخدم يعود إليه بشكل متكرر. في الواقع، يفضّل النظام إيقاف التطبيق الذي تم استخدامه سابقًا (PREV_APP_ADJ = 700) بدلاً من إيقاف مشغّل التطبيقات، لأنّ إيقاف مشغّل التطبيقات سيؤدي إلى تجربة مستخدم بطيئة عند الخروج من أي تطبيق، إذ سيحتاج المستخدم إلى الانتظار حتى يتم بدء تشغيل مشغّل التطبيقات. - محرّر أسلوب الإدخال (IME): عند الكتابة، يرتبط النظام بتطبيق لوحة المفاتيح الذي اخترته (مثل Gboard). يؤدي ذلك إلى إبقاء عملية لوحة المفاتيح في حالة نشطة حتى إذا تم إخفاء لوحة المفاتيح مؤقتًا. يضمن ذلك إمكانية إعادة ظهور لوحة المفاتيح على الفور عند النقر على حقل نص آخر.
- عمليات الدفع باستخدام تقنية NFC: عند الدفع باستخدام هاتفك، يرتبط النظام بخدمة الدفع باستخدام تقنية NFC (مثل "محفظة Google"). وغالبًا ما تتضمّن هذه المعاملات متطلبات صارمة في الوقت الفعلي من جهاز التاجر. إذا كان يجب إعادة تشغيل تطبيق الدفع، قد تنتهي مهلة المعاملة ويتعذّر إجراؤها.
المفاضلة بين الأداء والبطارية
على الرغم من أنّ عمليات الربط ضرورية لتحقيق الأداء الصحيح، فإنّها تؤثر سلبًا في سلامة ذاكرة النظام.
- انخفاض المرونة: كل عملية مرتبطة هي عملية لا يمكن لعملية إغلاق التطبيقات بسبب نقص الذاكرة إيقافها بسهولة. ويقلّل ذلك من "مساحة التخزين المؤقت" للعمليات المخزّنة مؤقتًا التي يمكن للنظام استخدامها لإخلاء مساحة في الذاكرة عند الحاجة.
- تفاقم مشكلة انخفاض الأداء: إذا تم ربط عدد كبير جدًا من العمليات، قد يجد النظام نفسه بدون أي عمليات خلفية يمكن إيقافها. عندما يزداد الضغط على الذاكرة، سينخفض الأداء بشكل أسرع بكثير، لأنّ النظام سيضطر إلى إنهاء عمليات أكثر أهمية أو إتلاف ذاكرة التخزين المؤقت للصفحة.
← المنطقة المحلية | ↑ للأعلى | على مستوى النظام →