سلاسل المحادثات والذاكرة

في كل مرة ينشئ فيها تطبيقك سلسلة محادثات جديدة، يجب على نظام التشغيل تخصيص ذاكرة لدعمها. على الرغم من أنّ سلاسل المحادثات تُعتبر بشكل عام "خفيفة" مقارنةً بالعمليات الكاملة، فإنّ تكلفتها على الذاكرة ليست صفرًا. يُعدّ تسرُّب سلاسل المحادثات طريقة شائعة جدًا لتسرُّب الذاكرة على Android.

تكلفة سلسلة المحادثات

عند إنشاء سلسلة محادثات على Android، يستهلك مكوّنان رئيسيان الذاكرة:

  1. مكدّس الذاكرة الأصلي: تخصّص مكتبة pthread مكدّس ذاكرة لسلسلة التعليمات لتخزين المتغيّرات المحلية وإطارات الاستدعاء. على Android، يكون هذا عادةً 1 ميغابايت بشكل افتراضي.
  2. بُنى JVM/Kernel الداخلية: يجب أن يخصّص وقت تشغيل Android (ART) ونواة Linux بُنى بيانات (مثل عناصر pthread_internal_t وjava.lang.Thread) لتتبُّع سلسلة التعليمات وإدارتها.

ذاكرة المكدّس وmmap

من المهم فهم أنّ Android يخصّص حزمة الذاكرة الأصلية بسعة 1 ميغابايت باستخدام mmap مع علامات MAP_ANONYMOUS | MAP_NORESERVE.

يعني ذلك أنّ نظام التشغيل يحجز 1 ميغابايت من مساحة عنوان الذاكرة الافتراضية، ولكنّه لا يخصّص 1 ميغابايت من ذاكرة الوصول العشوائي الفعلية على الفور. يتم تخصيص الذاكرة الفعلية (الترحيل) فقط عندما ينفّذ سلسلة التعليمات البرمجية فعليًا ويدفع البيانات إلى المكدس. فالمؤشر الذي لا ينفّذ أي إجراء سيستهلك قدرًا ضئيلاً جدًا من ذاكرة الوصول العشوائي (RAM) المادية لمجموعة البيانات.

تمرين عملي: سلاسل المحادثات المسرَّبة

سنستخدم نموذج تطبيق MemoryLab لملاحظة ما يحدث عندما ينشئ أحد التطبيقات مئات سلاسل المحادثات غير النشطة.

1. الإطلاق والبيانات المرجعية

شغِّل التطبيق واقرأ الذاكرة الأساسية:

adb shell am start -W -n com.android.memorylab/.MainActivity
adb shell dumpsys meminfo -s com.android.memorylab

اطّلِع على الصفَّين Stack وNative Heap في الناتج. ومن المرجّح أن تكون صغيرة.

2. إنشاء 100 سلسلة محادثات

انقر على الزر إنشاء 100 سلسلة محادثات. سينشئ التطبيق 100 سلسلة محادثات جديدة. لضمان نقل ذاكرة المكدّس فعليًا إلى ذاكرة الوصول العشوائي (RAM) (حتى نتمكّن من رؤيتها في أدواتنا)، يخصّص كل سلسلة محادثات مصفوفة صغيرة بحجم 10 كيلوبايت ويكتبها في المكدّس الخاص به قبل أن يبدأ الانتظار.

شغِّل الأمر meminfo مرة أخرى أثناء تشغيل سلاسل المحادثات:

adb shell dumpsys meminfo -s com.android.memorylab

النتائج:

قارِن الناتج الجديد بالناتج الأساسي. ستلاحظ زيادات كبيرة أثناء نشاط سلاسل المحادثات:

  • Stack: زاد حجم الملف بمقدار ميغابايت أو أكثر. يمثّل هذا الصفحات الفعلية المخصّصة لمجموعات سلاسل المحادثات البالغ عددها 100 (كل منها يلمس 10 كيلوبايت على الأقل).
  • ‫Native Heap / Private Other: زادت بسبب هياكل pthread الداخلية التي يخصّصها النظام لكل سلسلة محادثات.

لإجراء عملية التنظيف، انقر على الزر إتلاف جميع سلاسل المحادثات.

3- عرض سلاسل المحادثات في Perfetto

تُعدّ Perfetto أداة ممتازة لتتبُّع دورات حياة سلاسل المحادثات وعددها بمرور الوقت.

لقطة شاشة لواجهة مستخدم Perfetto تعرض مسار عدّاد يتضمّن عدد سلاسل المحادثات النشطة، وسلاسل المحادثات التي تبدأ وتنتهي في تطبيق memorylab

‫PerfettoSQL لتحليل سلاسل المحادثات

يمكنك الاستعلام عن التتبُّع لمعرفة عدد سلاسل المحادثات التي أنشأها التطبيق بالضبط:

SELECT p.name AS process_name, COUNT(t.id) as thread_count
FROM thread t JOIN process p USING (upid)
WHERE p.name = 'com.android.memorylab' AND t.name LIKE 'LeakedThread-%';

يمكن استخدام طلب مثل هذا لإنشاء مسار تصحيح أخطاء مع عدّاد كما هو موضّح في لقطة الشاشة.


← رمز التطبيق | ↑ للأعلى | الموقع الجغرافي →