الوحدة 8: الذاكرة الافتراضية

Virtual Memory

📚 استنادًا إلى الفصل الثامن من كتاب: Operating Systems: Internals and Design Principles – William Stallings – الإصدار التاسع

أهداف الوحدة

  • فهم مفهوم الذاكرة الافتراضية وكيفية عملها.
  • التعرف على هياكل العتاد (MMU, Page Table, TLB) ودورها في الذاكرة الافتراضية.
  • استيعاب برمجيات نظام التشغيل المسؤولة عن إدارة الذاكرة الافتراضية (Demand Paging, Page Replacement).
  • مقارنة آليات إدارة الذاكرة الافتراضية في أنظمة التشغيل المختلفة (Linux, Windows, Android, Unix).
  • فهم التحديات المتعلقة بالأداء مثل Thrashing وكيفية معالجتها.

1️⃣ هياكل العتاد والرقابة (Hardware and Control Structures)

الذاكرة الافتراضية هي تقنية ثورية تمكن نظام التشغيل من تنفيذ برامج أكبر من حجم الذاكرة الفعلية (RAM) المتاحة. تعتمد هذه التقنية بشكل كبير على دعم العتاد (Hardware) لتحويل العناوين وإدارة الصفحات.

🔍 كيف تعمل الذاكرة الافتراضية على مستوى العتاد؟

  • العنوان الظاهري (Virtual Address):

    هو العنوان الذي يراه البرنامج ويستخدمه للوصول إلى البيانات والتعليمات. كل عملية لديها مساحة عنوان افتراضية خاصة بها، تبدأ عادةً من الصفر وتكون كبيرة جدًا (مثلاً 4 جيجابايت في الأنظمة 32 بت، أو تيرابايت في الأنظمة 64 بت)، بغض النظر عن حجم الذاكرة الفعلية المتاحة.

  • العنوان الفعلي (Physical Address):

    هو العنوان الحقيقي في الذاكرة الرئيسية (RAM) حيث يتم تخزين البيانات والتعليمات فعليًا. هذا هو العنوان الذي تستخدمه وحدة الذاكرة للوصول إلى البيانات.

  • وحدة إدارة الذاكرة (Memory Management Unit - MMU):

    هي مكون عتادي حيوي موجود داخل المعالج (CPU) أو بالقرب منه. دورها الأساسي هو تحويل العناوين الظاهرية التي يولدها المعالج إلى عناوين فيزيائية يمكن للذاكرة الرئيسية فهمها والوصول إليها. تحدث هذه العملية بسرعة فائقة لضمان أداء عالٍ.

  • جدول الصفحات (Page Table):

    هو بنية بيانات رئيسية يحتفظ بها نظام التشغيل في الذاكرة الرئيسية. لكل عملية، يوجد جدول صفحات خاص بها. يحتوي هذا الجدول على إدخالات (Page Table Entries - PTEs) تربط كل صفحة منطقية (من مساحة العنوان الظاهرية للعملية) بإطار فيزيائي معين (Frame) في الذاكرة الرئيسية. إذا كانت الصفحة غير موجودة في الذاكرة الفعلية (أي أنها في القرص)، فإن إدخال جدول الصفحات يشير إلى ذلك.

  • ذاكرة التخزين المؤقت للترجمة (Translation Lookaside Buffer – TLB):

    هي ذاكرة مخبأة (Cache) صغيرة وسريعة جدًا، موجودة داخل وحدة MMU. تُستخدم TLB لتسريع عملية تحويل العناوين الظاهرية إلى فيزيائية. تخزن TLB أحدث الإدخالات المستخدمة من جدول الصفحات. عندما يطلب المعالج عنوانًا ظاهريًا، يتم البحث عنه أولاً في TLB. إذا وُجد (TLB Hit)، يتم التحويل بسرعة كبيرة. إذا لم يُوجد (TLB Miss)، يتم الوصول إلى جدول الصفحات في الذاكرة الرئيسية، ثم يُضاف الإدخال إلى TLB للاستخدام المستقبلي.

🧠 المفهوم الأساسي: تعتمد الذاكرة الافتراضية على مبدأ أن البرنامج لا يحتاج إلى أن يكون محملاً بالكامل في الذاكرة الرئيسية لكي يتم تنفيذه. يتم تحميل أجزاء من البرنامج (عادةً على شكل صفحات) فقط إلى الذاكرة الفعلية عند الحاجة إليها. الأجزاء غير النشطة تُخزّن مؤقتًا في ملف تبادل (Swap File) أو منطقة تبادل (Swap Space) على القرص الصلب. عندما تحاول العملية الوصول إلى جزء من البرنامج غير موجود في الذاكرة الفعلية، يحدث حدث يُعرف بـ "Page Fault" (خطأ الصفحة)، والذي يتولى نظام التشغيل معالجته.


2️⃣ برمجيات نظام التشغيل (OS Software)

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

مهام نظام التشغيل الرئيسية في إدارة الذاكرة الافتراضية:

  • تحميل الصفحات عند الطلب (Demand Paging):

    هذه هي التقنية الأساسية للذاكرة الافتراضية. بدلاً من تحميل البرنامج بأكمله في الذاكرة عند بدء تشغيله، يتم تحميل الصفحات فقط عندما تحاول العملية الوصول إليها لأول مرة. هذا يقلل من وقت بدء تشغيل البرامج ويسمح بتشغيل برامج أكبر من الذاكرة الفعلية.

  • التعامل مع أخطاء الصفحة (Page Fault Handling):

    عندما تحاول العملية الوصول إلى عنوان ظاهري يقع في صفحة غير موجودة حاليًا في الذاكرة الفعلية (أي أنها في القرص)، يحدث "Page Fault". يقوم نظام التشغيل بالخطوات التالية لمعالجة هذا الخطأ:

    1. يتم حفظ حالة المعالج والعملية الحالية.
    2. يتحقق نظام التشغيل من أن الوصول إلى العنوان قانوني.
    3. يحدد نظام التشغيل موقع الصفحة المطلوبة على القرص (عادةً في ملف التبادل).
    4. إذا كانت الذاكرة الفعلية ممتلئة، يختار نظام التشغيل صفحة "ضحية" (Victim Page) لإخراجها من الذاكرة إلى القرص.
    5. يتم تحميل الصفحة المطلوبة من القرص إلى إطار حر في الذاكرة الفعلية.
    6. يتم تحديث جدول الصفحات للعملية ليعكس الموقع الجديد للصفحة.
    7. تُعاد العملية إلى حالة "جاهزة" (Ready) لتستأنف تنفيذها من النقطة التي توقفت عندها.
  • استبدال الصفحات (Page Replacement):

    عندما تحدث Page Fault وتكون الذاكرة الفعلية ممتلئة، يجب على نظام التشغيل اختيار صفحة موجودة حاليًا في الذاكرة لإخراجها إلى القرص لإفساح المجال للصفحة الجديدة المطلوبة. تعتمد فعالية نظام الذاكرة الافتراضية بشكل كبير على خوارزمية استبدال الصفحات المستخدمة.

    🔁 أشهر خوارزميات استبدال الصفحات:

    • FIFO (First-In-First-Out - الداخل أولاً يخرج أولاً):

      تُخرج الصفحة الأقدم في الذاكرة. بسيطة في التنفيذ ولكنها قد تُخرج صفحات لا تزال قيد الاستخدام النشط.

    • LRU (Least Recently Used - الأقل استخدامًا مؤخرًا):

      تُخرج الصفحة التي لم تُستخدم لفترة أطول. تُعد فعالة جدًا لأنها تفترض أن الصفحات التي لم تُستخدم مؤخرًا لن تُستخدم قريبًا. تتطلب دعمًا عتاديًا أو برمجيات معقدة لتتبع استخدام الصفحات.

    • Optimal Replacement (الاستبدال الأمثل - نظريًا الأفضل):

      تُخرج الصفحة التي لن تُستخدم لأطول فترة زمنية في المستقبل. هذه الخوارزمية مستحيلة التنفيذ عمليًا لأنها تتطلب معرفة مسبقة بالمستقبل، ولكنها تُستخدم كمعيار لمقارنة أداء الخوارزميات الأخرى.

    • Clock Algorithm (خوارزمية الساعة):

      هي تقريب لخوارزمية LRU، وأكثر عملية في التنفيذ. تستخدم بت "مُستخدم" (Use Bit) لكل صفحة. عندما يتم الوصول إلى الصفحة، يتم تعيين بت الاستخدام الخاص بها إلى 1. عند البحث عن صفحة لإخراجها، يتم فحص الصفحات في ترتيب دائري. إذا كان بت الاستخدام 0، يتم إخراجها. إذا كان 1، يتم تعيينه إلى 0 ويتم الانتقال للصفحة التالية.

  • تحديد الصفحات التي يمكن إخراجها إلى القرص:

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

🧪 تمارين تفاعلية: Page Replacement Simulations


3️⃣ إدارة الذاكرة في أنظمة تشغيل مختلفة

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

🐧 Linux:

  • يستخدم Linux مفهوم Swap Space (مساحة التبادل) أو Swap File (ملف التبادل) على القرص الصلب لتخزين الصفحات غير النشطة.
  • يدعم خوارزميات استبدال صفحات متقدمة، وغالبًا ما يستخدم تقريبًا لخوارزمية LRU (مثل Clock Algorithm أو Modified Clock Algorithm) لتحسين الأداء.
  • يتعامل مع "OOM Killer" (Out-Of-Memory Killer) كآلية طوارئ. عندما تنفد الذاكرة تمامًا (RAM وSwap)، يقوم OOM Killer بإنهاء العمليات التي تستهلك أكبر قدر من الذاكرة لتحرير الموارد ومنع تعطل النظام بالكامل.

🪟 Windows:

  • يستخدم Windows ملفًا يسمى pagefile.sys على القرص الصلب كمساحة للذاكرة الافتراضية.
  • يدير الأولوية بين العمليات المختلفة عند تخصيص الذاكرة، مما يضمن أن العمليات ذات الأولوية العالية تحصل على الموارد اللازمة.
  • يُتيح للمستخدمين التحكم اليدوي في حجم الملف التبادلي (Page File Size) من خلال إعدادات النظام، مما يسمح بضبط الأداء حسب الحاجة.

📱 Android:

  • بما أن Android مبني على Linux Kernel، فإنه يعتمد على آليات الذاكرة الافتراضية الأساسية في Linux.
  • يستخدم تقنيات ضغط الذاكرة مثل ZRAM. ZRAM تنشئ قسمًا مضغوطًا في الذاكرة الرئيسية (RAM) يعمل كمساحة تبادل. بدلاً من نقل الصفحات إلى القرص البطيء، يتم ضغطها وتخزينها في هذا القسم المضغوط في RAM، مما يقلل من الاعتماد على التخزين البطيء ويحسن الأداء بشكل كبير على الأجهزة المحمولة ذات الذاكرة المحدودة.

💻 Unix / Solaris:

  • تُخصص مساحة تبادلية (Swap Space) عادةً أثناء عملية تمهيد النظام (Boot Process).
  • يوازن نظام التشغيل ديناميكيًا بين استخدام الذاكرة الرئيسية (RAM) ومساحة التبادل (Swap Space) لضمان أفضل أداء واستجابة للنظام.

📚 شرح موسّع: Linux Virtual Memory – Kernel Docs


4️⃣ مفاهيم وتقنيات داعمة

بالإضافة إلى المكونات الأساسية، هناك عدة مفاهيم وتقنيات أخرى تدعم عمل الذاكرة الافتراضية وتساهم في فعاليتها.

  • الترحيل (Swapping):

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

    الفرق بين Swapping وPaging: Swapping ينقل عمليات كاملة أو أجزاء كبيرة، بينما Paging ينقل صفحات صغيرة وثابتة الحجم.

  • الطلب الجزئي (Demand Paging):

    كما ذكرنا سابقًا، هي التقنية التي يتم فيها تحميل الصفحة إلى الذاكرة الفعلية فقط عند محاولة الوصول إليها لأول مرة (أي عند حدوث Page Fault). هذه التقنية هي أساس الذاكرة الافتراضية وتُحسن من استخدام الذاكرة ووقت بدء تشغيل البرامج بشكل كبير.

  • خطأ الصفحة (Page Fault):

    هو حدث (نوع من المقاطعة) يحدث عندما تحاول العملية الوصول إلى صفحة غير موجودة حاليًا في الذاكرة الرئيسية (RAM). يُشير هذا إلى أن الصفحة المطلوبة موجودة على القرص وتحتاج إلى تحميلها في الذاكرة قبل أن تتمكن العملية من متابعة تنفيذها. معالجة Page Fault هي مهمة أساسية لنظام التشغيل في بيئة الذاكرة الافتراضية.

  • مجموعة العمل (Working Set):

    هي مجموعة الصفحات التي تحتاجها العملية بنشاط في فترة زمنية معينة. يحاول نظام التشغيل الاحتفاظ بـ "مجموعة العمل" لكل عملية في الذاكرة الرئيسية قدر الإمكان لتجنب حدوث الكثير من أخطاء الصفحة (Page Faults) والتبديل المفرط (Thrashing). إذا كانت مجموعة العمل لعملية ما أكبر من الذاكرة الفعلية المتاحة لها، فقد يؤدي ذلك إلى تدهور الأداء.


5️⃣ الأداء والتحديات

على الرغم من الفوائد الكبيرة للذاكرة الافتراضية، إلا أنها تأتي مع تحديات محتملة تتعلق بالأداء إذا لم تُدار بشكل صحيح.

⚠️ المشاكل المحتملة:

  • التبديل المفرط (Thrashing):

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

  • معدل أخطاء الصفحة (Page Fault Rate):

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

  • الحمل الزائد (Overhead):

    معالجة أخطاء الصفحة، وتحديث جداول الصفحات، وإدارة TLB، وتنفيذ خوارزميات استبدال الصفحات، كلها تتطلب وقتًا وموارد من المعالج. إذا لم تكن هذه العمليات مُدارة جيدًا، فإن الحمل الزائد يمكن أن يقلل من الفوائد الكلية للذاكرة الافتراضية.

🧠 استراتيجيات تحسين الأداء:

  • تحسين خوارزميات استبدال الصفحات: استخدام خوارزميات أكثر ذكاءً (مثل LRU أو Clock Algorithm) لتقليل عدد أخطاء الصفحة.
  • زيادة حجم RAM الفعلي: ببساطة، إضافة المزيد من الذاكرة الرئيسية يمكن أن يقلل بشكل كبير من الحاجة إلى التبادل مع القرص ويقلل من فرص حدوث Thrashing.
  • استخدام تقنيات ضغط الذاكرة: مثل ZRAM في Android، حيث يتم ضغط الصفحات غير النشطة وتخزينها في الذاكرة الرئيسية بدلاً من نقلها إلى القرص.
  • تحسين حجم مجموعة العمل: محاولة تصميم البرامج بحيث تكون مجموعات العمل الخاصة بها صغيرة قدر الإمكان.

📚 مقال تقني: Understanding Thrashing – TechTarget

🧪 تطبيق عملي:

لفهم كيفية تفاعل نظامك مع الذاكرة الافتراضية، يمكنك استخدام الأوامر التالية في Shell بنظام Linux:

free -h        # لعرض استخدام الذاكرة والتبادل (RAM and Swap)
vmstat 1       # لمراقبة تبديل الصفحات (Page Swapping) ومعدل أخطاء الصفحة في الوقت الفعلي
swapon --show  # لمراجعة ملفات التبادل (Swap Files/Partitions) النشطة في نظامك

هذه الأوامر ستساعدك على رؤية كيفية استخدام الذاكرة الفعلية والافتراضية على نظامك، ومراقبة أي علامات على تباطؤ الأداء بسبب إدارة الذاكرة.


ملخص الوحدة

تُعد تقنية **الذاكرة الافتراضية (Virtual Memory)** ثورية في تصميم أنظمة التشغيل الحديثة، حيث تُوفر طريقة فعالة لتشغيل برامج تفوق حجم الذاكرة الرئيسية (RAM) وتُساعد على تعدد المهام بأداء أفضل. فهمنا كيف تعتمد هذه التقنية على **هياكل العتاد** مثل MMU وجداول الصفحات لتحويل العناوين، وكيف تقوم **برمجيات نظام التشغيل** بإدارة الصفحات من خلال **الطلب الجزئي (Demand Paging)** و**خوارزميات استبدال الصفحات** المختلفة. كما استعرضنا كيفية تطبيق هذه المفاهيم في أنظمة التشغيل الشائعة مثل Linux وWindows وAndroid. وأخيرًا، ناقشنا **التحديات المتعلقة بالأداء** مثل ظاهرة **التبديل المفرط (Thrashing)** وكيفية التخفيف منها لضمان استقرار وكفاءة النظام.