4.19. تجمعات الذاكرة

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

4.19.1. أنواع الذاكرة

يكشف متحكم OpenMV Cam الدقيق الحديث عن أربعة أنواع متمايزة من الذاكرة. الأول غير مرئي للتطبيق؛ أما الثلاثة الأخرى فهي تجمعات يمكن أن تأتي منها التخصيصات.

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

  • ذاكرة المعالج المقترنة بإحكام -- كتلة صغيرة من RAM موصولة مباشرة بوحدة المعالجة المركزية دون ناقل بينهما. وصول بدورة واحدة، لا تخفق أبداً، ولا تنتظر أبداً. التخصيصات التي تحتاج فعلاً إلى أسرع ذاكرة ممكنة -- حيث تهم كل دورة من زمن الاستجابة -- تأتي من هذا التجمع.

  • الذاكرة السريعة المدمجة في الشريحة -- بضع مئات من الكيلوبايت وحتى نحو ميغابايت من RAM، مدمجة داخل حزمة المتحكم الدقيق. زمن استجابة منخفض، وعرض نطاق عالٍ، لكن حجمها محدود. تقيم كومة MicroPython هنا حتى يبقى الوصول إلى كائنات Python سريعاً؛ كما تتشارك المخازن المؤقتة الأصغر للعمل التي تلمسها وحدة المعالجة المركزية كثيراً هذا التجمع.

  • الذاكرة المجمّعة الأبطأ -- على اللوحات التي تقرن المتحكم الدقيق بشريحة ذاكرة خارجية، عشرات الميغابايتات من RAM خارج الشريحة يُوصل إليها عبر الناقل الخارجي. أكبر بكثير، لكن كل عملية وصول تستغرق وقتاً أطول من الذاكرة المدمجة في الشريحة؛ تخفي ذاكرة التخزين المؤقت للبيانات الكثير من هذه التكلفة بالنسبة لمجموعات العمل التي يمكنها الاحتفاظ بها، وتظهر الفجوة في العمليات التي تجتاح بيانات أكبر من أن تخزَّن مؤقتاً. تُستخدم للتخصيصات التي يجب أن تكون كبيرة والتي يمكن لوحدة المعالجة المركزية أن تتحملها بسرعة أبطأ -- والأهم من ذلك، تجمع مخزن الإطارات.

تقع اللوحات في هذه العائلة على طيف: بعضها لا يملك سوى RAM مدمجة في الشريحة؛ وبعضها يقرن RAM المدمجة في الشريحة بكتلة خارجية أكبر بكثير. يُعامَل كل نوع من الأنواع الثلاثة القابلة للتخصيص بوصفه تجمع ذاكرة -- جزءاً تأتي منه التخصيصات -- ويُوسم بحيث يمكن لكل طلب أن يطلب نوع الذاكرة الذي يحتاجه فعلياً.

4.19.2. مخزن الإطارات الأساسي

مخزن الإطارات الذي يدعم snapshot() لا يطلب ذاكرة سريعة. إنه يطلب ذاكرة كافية -- لا أكثر. وهذا يضعه في أكبر تجمع متاح، فعلى لوحة تملك ذاكرة مدمجة في الشريحة وذاكرة خارجية معاً، يستقر مخزن الإطارات في الكتلة الخارجية.

مخزن إطارات بدقة كاملة وثلاثي التخزين المؤقت أكبر بكثير من أن يتسع في التجمع السريع المدمج في الشريحة على معظم الأجزاء؛ فالتجمع الأكبر هو الوحيد القادر على احتوائه على الإطلاق. تخفي ذاكرة التخزين المؤقت للبيانات في وحدة المعالجة المركزية الكثير من تكلفة كل عملية وصول عندما يعالج التطبيق الصورة، ومحرك DMA الذي يملأ مخزن الإطارات من المستشعر يواكب معدل بيانات المستشعر في كلتا الحالتين.

يُنتقى الحجم الدقيق الذي يأخذه مخزن الإطارات من قيم pixformat() وframesize() وعدد framebuffers() الحالية؛ وهو يكبر أو يصغر في كل مرة يتغير فيها أي منها.

4.19.3. مخازن إطارات المستشعرات الثانوية

تحصل أي نسخة ثانية من CSI على مخزن إطارات خاص بها، مخصَّص من التجمع نفسه الذي تستخدمه النسخة الأساسية. التجمع مشترك؛ أما المخازن المؤقتة فمستقلة. عادةً ما تكون بصمة المستشعر الثانوي أصغر بكثير من بصمة الأساسي، لأن المستشعرات الثانوية تعمل بدقات أدنى، فالذاكرة الإضافية التي يأخذها مخزن الإطارات الثاني تشكل جزءاً صغيراً من ذاكرة الأساسي.

4.19.4. مخزن إطارات البث

مخزن معاينة الصورة هو الاستثناء. فهو لا يُخصَّص من أي من التجمعات في وقت التشغيل؛ بل هو منطقة ثابتة محجوزة وقت البناء، بعنوان معروف وحجم معروف. وهذا يبقي مسار المعاينة بعيداً عن طريق كل تخصيص آخر -- إذ توجد المنطقة منذ الإقلاع ولا تتحرك أبداً.

4.19.5. كومة MicroPython

كائنات Python -- المتغيرات والقوائم والقواميس ونسخ الفئات وغلاف Image الذي يعيده استدعاء snapshot()، وكل سلسلة نصية وصف (tuple) ينشئها التطبيق -- تقيم على كومة MicroPython المُجمَّعة للنفايات، وهي منفصلة عن تجمعات ذاكرة الكاميرا. الكومة المُجمَّعة للنفايات (GC) هي منطقة ذاكرة يديرها MicroPython بنفسه: يخصص كود Python منها ضمنياً في كل مرة يُنشأ فيها كائن، ويفحص MicroPython الكومة دورياً ويستعيد المساحة التي تشغلها الكائنات التي لم يعد التطبيق يشير إليها، فلا يضطر التطبيق أبداً إلى تحرير أي شيء يدوياً.

تُخصَّص منطقة مكرسة للكومة المُجمَّعة للنفايات عند الإقلاع، وتوضع عادةً في الذاكرة السريعة المدمجة في الشريحة حتى يبقى وصول Python سريعاً، مع امتداد اختياري إلى الكتلة الخارجية الأكبر على اللوحات التي تحتاج إلى مساحة إضافية لهياكل البيانات الكبيرة.

الكائن Image الذي تعيده snapshot() هو كائن غلاف صغير على الكومة المُجمَّعة للنفايات؛ أما بيانات البكسل الأساسية فتقيم في مخزن الإطارات داخل أحد تجمعات الكاميرا. ولا يتنافس الاثنان أبداً على الذاكرة نفسها.

4.19.6. تجميع كل ذلك معاً

توجيه كل نوع من التخصيص إلى التجمع الصحيح -- المخازن المؤقتة الكبيرة إلى التجمع الأكبر حيث تتسع، والبيانات الحساسة لزمن الاستجابة إلى التجمعات الأسرع، وكومة Python إلى منطقتها الخاصة، والمعاينة إلى موضعها المحجوز -- هو ما يجعل من الممكن تشغيل خط التقاط بدقة كاملة وقناة معاينة وبرنامج Python نصي غير بسيط جنباً إلى جنب على أجزاء لا تملك سوى بضعة ميغابايتات من الذاكرة السريعة إجمالاً.