debugging كل - ما هي البايت الخاصة ، البايت الظاهري ، مجموعة العمل؟




بالانجليزي معنى (5)

أحاول استخدام الأداة المساعدة Windows perfmon لتصحيح أخطاء الذاكرة في عملية.

هذه هي الطريقة التي يفسر بها perfmon الشروط:

مجموعة العمل هي الحجم الحالي ، بالبايت ، لمجموعة العمل الخاصة بهذه العملية. مجموعة العمل عبارة عن مجموعة من صفحات الذاكرة التي تم لمسها مؤخرًا بواسطة مؤشرات الترابط في العملية. إذا كانت الذاكرة الخالية في الكمبيوتر أعلى من الحد الأدنى ، فسيتم ترك الصفحات في مجموعة العمل الخاصة بعملية حتى إذا لم تكن قيد الاستخدام. عندما تنخفض الذاكرة الخالية إلى أقل من الحد الأدنى ، يتم تقليم الصفحات من مجموعات العمل. إذا ﻟﺰم اﻷﻣﺮ ، ﻓﺴﻴﺘﻢ إﺻﻼﺣﻪ ﺑﻄﺮﻳﻘﺔ ﺳﻠﻴﻤﺔ إﻟﻰ اﻟﻤﺠﻤﻮﻋﺔ اﻟﻌﺎﻣﻠﺔ ﻗﺒﻞ اﻟﺨﺮوج ﻣﻦ اﻟﺬاآﺮة اﻟﺮﺋﻴﺴﻴﺔ.

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

وحدات البايت الخاصة هي الحجم الحالي ، بالبايت ، من الذاكرة التي تخصصها هذه العملية والتي لا يمكن مشاركتها مع العمليات الأخرى.

هذه هي الأسئلة التي لدي:

هل البايتات الخاصة هي التي يجب أن أقيسها للتأكد من أن العملية لها أي تسريبات لأنها لا تنطوي على أي مكتبات مشتركة وأي تسريبات ، إذا حدثت ، ستأتي من العملية نفسها؟

ما هي الذاكرة الإجمالية التي تستهلكها العملية؟ هل البايت الظاهري أم هو مجموع البايت الظاهري ومجموعة العمل؟

هل هناك أي علاقة بين وحدات البايت الخاصة ومجموعة العمل والبايت الظاهري؟

هل هناك أي أدوات أخرى تعطي فكرة أفضل عن استخدام الذاكرة؟


Answers

هناك مناقشة شيقة هنا: http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/307d658a-f677-40f2-bdef-e6352b0bfe9e/ فهمي لهذا الموضوع هو أن تحرير التخصيصات الصغيرة لا تنعكس في وحدات البايت الخاصة أو مجموعة العمل.

قصة طويلة قصيرة:

لو اتصلت

p=malloc(1000);
free(p);

ثم تعكس وحدات البايت الخاصة التخصيص فقط ، وليس إلغاء التوزيع.

لو اتصلت

p=malloc(>512k);
free(p);

ثم تعكس وحدات البايت الخاصة بشكل صحيح التخصيص و deallocation.


تم كسر تعريف عدادات perfmon منذ البداية ولسبب ما يبدو أن يصعب للغاية.

نظرة عامة جيدة على إدارة ذاكرة Windows متوفرة في الفيديو " Mysteries of Memory Management Revealed " على MSDN: وهو يغطي موضوعات أكثر من اللازم لتتبع تسرب الذاكرة (مثل إدارة مجموعة العمل) ولكنه يعطي تفاصيل كافية في الموضوعات ذات الصلة.

لإعطائك تلميحًا عن المشكلة المتعلقة بأوصاف العداد الخاص بـ perfmon ، إليك القصة الداخلية عن البايتات الخاصة من " عداد الأداء البايت الخاص - احذر! " على MSDN:

س: متى يكون البايت الخاص ليس البايت الخاص؟

ج: عندما لا تكون مقيمة.

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

من " تخطيط الأداء " على MSDN:

3.3 وحدات البايت الخاصة

3.3.1 الوصف

يتم تعريف الذاكرة الخاصة كذاكرة مخصصة لعملية لا يمكن مشاركتها بواسطة العمليات الأخرى. هذه الذاكرة أكثر تكلفة من الذاكرة المشتركة عند تنفيذ العديد من هذه العمليات على جهاز. الذاكرة الخاصة في dlls (التقليدية) غير المدارة عادة ما تشكل statics C ++ وهي من ترتيب 5٪ من إجمالي مجموعة العمل من دلل.


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

تشير وحدات البايت الخاصة إلى مقدار الذاكرة التي تطلبها العملية القابلة للتنفيذ - وليس بالضرورة الكمية التي تستخدمها بالفعل . وهي "خاصة" لأنها (عادةً) تستبعد ملفات الذاكرة المعينة (مثل DLLs المشتركة). ولكن - هنا هو المصيد - أنها لا تستبعد بالضرورة الذاكرة المخصصة من قبل تلك الملفات . لا توجد طريقة لمعرفة ما إذا كان التغيير في البايتات الخاصة يرجع إلى الملف التنفيذي نفسه أو بسبب مكتبة مرتبطة. البايتات الخاصة ليست أيضًا ذاكرة فعلية بشكل حصري ؛ يمكن تقسيمها إلى قرص أو في قائمة صفحة الانتظار (أي لم تعد قيد الاستخدام ، ولكن لا يتم تقسيمها إلى صفحات بعد).

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

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

إذن فالعلاقات هي:

  • وحدات البايت الخاصة هي ما خصصه تطبيقك فعلاً ، ولكنها تتضمن استخدام ملف ترحيل الصفحات ؛
  • مجموعة العمل هي ملفات Bytes غير Bytes خاص + الذاكرة المعينة؛
  • البايت الظاهري هي مجموعة العمل بالإضافة إلى ترحيل وحدات البايت الخاصة وقوائم الانتظار.

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

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

أحد الأدوات الأكثر فعالية لكشف / تصحيح تسرب الذاكرة في Windows هو في الواقع Visual Studio (ينتقل الارتباط إلى صفحة حول استخدام VS لتسربات الذاكرة ، وليس صفحة المنتج). تنقية عقلانية هو احتمال آخر. لدى Microsoft أيضًا مستند أفضل الممارسات العامة حول هذا الموضوع. هناك المزيد من الأدوات المدرجة في هذا السؤال السابق .

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


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

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

تسأل عن توصية الأداة: أوصي بـ Memory Validator. قادرة على مراقبة التطبيقات التي تجعل مليارات من مخصصات الذاكرة.

http://www.softwareverify.com/cpp/memory/index.html

إخلاء المسؤولية: لقد قمت بتصميم Memory Validator.


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

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

الآن يتلخص السؤال الرئيسي في كيفية إدارة الذاكرة. ما الذي يحكم بالضبط أين ستوجد البيانات التي تنتمي إلى برنامج معين في الذاكرة؟

الحل المقترح 1 : دع البرامج الفردية تحدد صراحة عنوان الذاكرة الذي ستستخدمه في الجهاز. لنفترض أن Photoshop يعلن أنه سيستخدم دومًا عناوين الذاكرة التي تتراوح من 0 إلى 1023 (تخيل الذاكرة كمصفوفة خطية للبايتات ، لذا تكون البايتة الأولى في الموقع 0 ، 1024 بايت موجودة في الموقع 1023 ) - أي تشغل ذاكرة 1 GB . وبالمثل ، تعلن VLC أنها ستشغل نطاق الذاكرة من 1244 إلى 1876 ، إلخ.

مزايا:

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

سلبيات:

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

  2. ليس من الممكن منع تشويش الذاكرة. هناك الملايين من البرامج هناك ، حتى لو تم تخصيص كل واحد منهم فقط ذاكرة 1 kB ، فإن إجمالي الذاكرة المطلوبة سيتجاوز 16 GB ، وهو أكثر مما تقدمه معظم الأجهزة. كيف يمكن ، إذن ، تخصيص برامج مختلفة لفتحات الذاكرة التي لا تتعدى مناطق بعضها البعض؟ أولاً ، لا يوجد سوق برمجيات مركزي يمكن أن ينظم ذلك عند إصدار برنامج جديد ، يجب أن يعين نفسه هذه الذاكرة الكبيرة من هذه المنطقة غير المشغولة بعد ، وثانياً ، حتى لو كان هناك ، ليس من الممكن القيام بذلك لأن لا. البرامج غير محدودة عمليا (وبالتالي تتطلب ذاكرة غير محدودة لاستيعاب كل منها) ، وذاكرة الوصول العشوائي (RAM) المتوفرة على أي جهاز غير كافية لاستيعاب حتى جزء مما هو مطلوب ، مما يجعل من الحتمي التعدي على حدود الذاكرة في برنامج واحد على ذلك من آخر. ما الذي يحدث عند تعيين Photoshop لمواقع الذاكرة من 1 إلى 1023 ويتم تعيين VLC من 1000 إلى 1676 ؟ ماذا لو قام Photoshop بتخزين بعض البيانات في الموقع 1008 ، ثم يقوم VLC بالكتابة فوق ذلك مع بياناته الخاصة ، وما بعده يقوم Photoshop بالوصول إليه معتقدًا أنه نفس البيانات المخزنة هناك سابقًا؟ كما يمكنك أن تتخيل ، سيحدث أشياء سيئة.

بكل وضوح ، وكما ترون ، فإن هذه الفكرة ساذجة نوعًا ما.

الحل المقترح 2 : لنجرب نظامًا آخر - حيث سيحقق نظام التشغيل غالبية إدارة الذاكرة. البرامج ، كلما تطلبت أي ذاكرة ، ستطلب فقط نظام التشغيل ، وسيتوافق نظام التشغيل وفقًا لذلك. يضمن نظام التشغيل OS أنه كلما طلبت عملية جديدة للذاكرة ، سيقوم بتخصيص الذاكرة من عنوان البايت الأقل الممكن (كما ذكرنا سابقًا ، يمكن تخيل ذاكرة الوصول العشوائي كمصفوفة خطية من وحدات البايت ، لذا بالنسبة لذاكرة وصول عشوائي 4 GB ، فإن نطاق العناوين لقيمة بايت من 0 إلى 2^32-1 ) في حالة بدء العملية ، وإلا إذا كانت عملية قيد التشغيل تتطلب الذاكرة ، فسيتم تخصيصها من موقع الذاكرة الأخير حيث لا تزال تلك العملية موجودة. بما أن البرامج سوف تصدر عناوين دون النظر إلى عنوان الذاكرة الفعلي الذي سيتم تخزين البيانات فيه ، سيضطر نظام التشغيل إلى الحفاظ على رسم الخرائط ، لكل برنامج ، للعنوان الذي يرسله البرنامج إلى العنوان الفعلي الفعلي (ملاحظة: هذا هو أحد السببين الذي نسميه هذا المفهوم " Virtual Memory ليست مهتمة بعناوين الذاكرة الحقيقية حيث يتم تخزين بياناتها ، فإنها تبصقون العناوين على الطاير ، ويجد نظام التشغيل المكان المناسب لتلائمها. العثور عليه في وقت لاحق إذا لزم الأمر).

لنفترض أن الجهاز قد تم تشغيله للتو ، تم تشغيل نظام التشغيل للتو ، في الوقت الحالي لا توجد أي عملية أخرى قيد التشغيل (تجاهل نظام التشغيل ، الذي يعد أيضًا عملية!) ، وقررت إطلاق VLC . لذلك يتم تخصيص VLC جزءًا من ذاكرة الوصول العشوائي (RAM) من عناوين البايت الأقل. جيد. الآن أثناء تشغيل الفيديو ، يلزمك بدء تشغيل المتصفح لعرض بعض صفحات الويب. ثم تحتاج إلى تشغيل برنامج " المفكرة" للتدوين في بعض النصوص. ثم كسوف للقيام ببعض الترميز .. قريبا جدا تستهلك ذاكرة 4 GB ، وذاكرة الوصول العشوائي تبدو هكذا:

المشكلة 1: الآن لا يمكنك بدء أي عملية أخرى ، لأنه يتم استخدام كافة ذاكرة الوصول العشوائي. لذلك يجب كتابة البرامج التي تحافظ على الذاكرة القصوى في الذهن (عمليا سيكون أقل متوفرة ، حيث أن البرامج الأخرى سوف تعمل بشكل متوازي كذلك!). وبعبارة أخرى ، لا يمكنك تشغيل تطبيق يستهلك ذاكرة عالية في جهاز الكمبيوتر 1 GB المتداعي.

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

لنفترض أن هذين اثنين يحرر مساحة 700 MB - ( 400 + 300 ) ميغابايت. الآن تحتاج إلى تشغيل Opera ، الذي سيشغل مساحة 450 MB . حسنا ، لديك أكثر من 450 MB المساحة المتاحة ، ولكن ... أنها ليست متجاورة ، فهي مقسمة إلى أجزاء فردية ، لا شيء منها كبير بما يكفي لتناسب 450 MB . لذلك أنت تضرب على فكرة رائعة ، دعنا نقل جميع العمليات أدناه إلى أكبر قدر ممكن ، والتي ستترك مساحة فارغة 700 MB في قطعة واحدة في الجزء السفلي. وهذا ما يسمى compaction . عظيم ، إلا أن ... جميع العمليات التي يتم تشغيلها هناك. يعني نقلها نقل عنوان جميع محتوياتها (تذكر ، يحافظ نظام التشغيل على رسم خريطة للذاكرة من قبل البرنامج إلى عنوان الذاكرة الفعلي. تخيل أن البرنامج قد قام بإدراج عنوان 45 مع البيانات 123 ، وأن نظام التشغيل قام بتخزينه في الموقع 2012 وإنشاء مدخل في الخريطة ، ورسم الخرائط من 45 إلى 2012 إذا تم نقل البرنامج الآن في الذاكرة ، فإن ما كان في الموقع 2012 لن يكون عام 2012 ، ولكن في موقع جديد ، ويجب على نظام التشغيل تحديث الخريطة وفقا لذلك لرسم خريطة 45 إلى العنوان الجديد ، بحيث يمكن للبرنامج الحصول على البيانات المتوقعة ( 123 ) عندما يستعلم عن موقع الذاكرة 45 وفيما يتعلق بالبرنامج ، كل ما يعرفه هو أن العنوان 45 يحتوي على البيانات 123 !)! تخيل عملية تشير إلى متغير محلي i . في الوقت الذي يتم الوصول إليه مرة أخرى ، تغير عنوانه ، ولن يكون بإمكانه العثور عليه بعد الآن. نفس الشيء سيحافظ على جميع الوظائف ، الأجسام ، المتغيرات ، أساسًا كل شيء له عنوان ، وسيعني نقل العملية تغيير عنوان كل منها. مما يقودنا إلى:

المشكلة الثانية: لا يمكنك نقل العملية. إن قيم كل المتغيرات والوظائف والأشياء داخل تلك العملية لها قيم ضمنية مثل spat out بواسطة المحول البرمجي أثناء التحويل البرمجي ، تعتمد العملية على كونها في نفس المكان خلال عمرها الافتراضي ، وتغييرها باهظ الثمن. نتيجة لذلك ، تترك العمليات وراء " holes " الكبيرة عندما تخرج. وهذا ما يسمى External Fragmentation .

غرامة. لنفترض بطريقة ما ، وبطريقة معجزة ، يمكنك إدارة العمليات. الآن هناك 700 MB من المساحة الحرة في الأسفل:

تتناسب Opera بسلاسة في الأسفل. الآن تبدو ذاكرة الوصول العشوائي الخاصة بك على النحو التالي:

جيد. كل شيء يبدو بخير. ومع ذلك ، لا توجد مساحة كبيرة متبقية ، والآن تحتاج إلى تشغيل Chrome مرة أخرى ، وهو ذاكرة خنازير معروفة! تحتاج إلى الكثير من الذاكرة لتبدأ ، وبالكاد تبقى لديك أي شيء ... ما عدا أنك تلاحظ الآن أن بعض العمليات ، التي كانت تشغل مساحة كبيرة في البداية ، لا تحتاج الآن إلى مساحة كبيرة. قد يكون لديك توقف الفيديو الخاص بك في VLC ، وبالتالي فإنه لا يزال يحتل بعض المساحة ، ولكن ليس بقدر ما هو مطلوب أثناء تشغيل فيديو عالي الدقة. وبالمثل للمفكرة والصور . تبدو ذاكرة الوصول العشوائي الآن كما يلي:

Holes ، مرة أخرى! العودة إلى المربع الأول! باستثناء ، في السابق ، حدثت الثقوب بسبب العمليات التي تنتهي ، والآن يرجع ذلك إلى العمليات التي تتطلب مساحة أقل من ذي قبل! ولديك نفس المشكلة مرة أخرى ، فإن holes مجتمعة تعطي مساحة أكبر من المطلوب ، ولكنها منتشرة في جميع أنحاء ، وليس الكثير من استخدامها في عزلة. لذلك عليك أن تقوم بتحويل تلك العمليات مرة أخرى ، عملية مكلفة ، ومتكررة للغاية في ذلك ، لأن العمليات ستقلل من حيث الحجم في كثير من الأحيان مدى حياتها.

المشكلة 3: قد تخفض العمليات ، على مدى عمرها ، في الحجم ، تاركة وراءها مساحة غير مستخدمة ، والتي إذا لزم استخدامها ، ستتطلب عملية مكلفة لنقل العديد من العمليات. وهذا ما يسمى Internal Fragmentation .

حسنًا ، حتى الآن ، يعمل نظام التشغيل لديك على ما هو مطلوب ، وينقل العمليات حوله ويبدأ Chrome ، وبعد مرور بعض الوقت ، تبدو ذاكرة الوصول العشوائي كما يلي:

رائع. الآن افترض أنك مرة أخرى تستأنف مشاهدة الصورة الرمزية في VLC . متطلبات الذاكرة سوف تطلق النار! ولكن ... لا توجد مساحة متبقية للنمو ، حيث يتم تحريك " المفكرة" في قاعها. لذا ، مرة أخرى ، يجب أن تتحرك جميع العمليات أدناه حتى وجد VLC مساحة كافية!

المشكلة 4: إذا كانت العمليات تحتاج إلى النمو ، فستكون عملية مكلفة للغاية

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

المشكلة 5: تبقى الوظائف المندمجة في I / O تحتل مساحة ذاكرة الوصول العشوائي (RAM) ، مما يؤدي إلى نقص استخدام ذاكرة الوصول العشوائي (RAM) ، والتي كان من الممكن استخدامها من قبل وحدات المعالجة المركزية CPU في نفس الوقت.

لذلك ، كما نرى ، لدينا الكثير من المشاكل حتى مع نهج الذاكرة الظاهرية.

هناك طريقتان لمعالجة هذه المشاكل - paging segmentation . دعونا نناقش paging . في هذا الأسلوب ، يتم تعيين مساحة العنوان الظاهرية لعملية إلى الذاكرة الفعلية في pages تسمى chunks. حجم page النموذجي هو 4 kB . تتم المحافظة على التعيين بواسطة شيء يسمى page table ، مع إعطاء عنوان افتراضي ، كل ما علينا فعله الآن هو معرفة page التي ينتمي إليها العنوان ، ثم من page table ، والعثور على الموقع المقابل لتلك page في الذاكرة الفعلية الفعلية ( المعروفة باسم frame ) ، وبالنظر إلى أن إزاحة العنوان الظاهري داخل page هي نفسها بالنسبة page وكذلك frame ، يمكنك معرفة العنوان الفعلي من خلال إضافة هذا الإزاحة إلى العنوان الذي يتم إرجاعه بواسطة page table . فمثلا:

على اليسار هو مساحة العنوان الظاهرية لعملية. قل مساحة العنوان الظاهرية تتطلب 40 وحدة من الذاكرة. إذا كانت مساحة العنوان الفعلي (على اليمين) تحتوي على 40 وحدة من الذاكرة أيضًا ، فقد كان من الممكن تعيين كل الموقع من اليسار إلى موقع على اليمين ، وكنا سنكون سعداء بذلك. ولكن كما كان سيئ الحظ سيحصل ، ليس فقط على الذاكرة الفعلية (24 وحدة ذاكرة) متوفرة فقط ، بل يجب مشاركتها بين عمليات متعددة أيضاً! حسنا ، دعونا نرى كيف نفعل مع ذلك.

عند بدء العملية ، قل طلب الوصول إلى الذاكرة للموقع 35 . هنا حجم الصفحة هو 8 (كل page تحتوي على 8 مواقع ، مساحة العنوان الظاهري بالكامل من 40 موقعاً يحتوي بالتالي على 5 صفحات). لذلك ينتمي هذا الموقع لصفحة لا. 4 ( 35/8 ). ضمن هذه page ، يحتوي هذا الموقع على إزاحة من 5 ( 35%8 ). لذلك يمكن تحديد هذا الموقع بواسطة المجموعة (pageIndex, offset) = (4,3) . هذا هو مجرد البداية ، لذلك لا يتم تخزين أي جزء من العملية في الذاكرة الفعلية الفعلية حتى الآن. لذا ، فإن page table ، الذي يحافظ على تعيين الصفحات على اليسار إلى الصفحات الفعلية على اليمين (حيث تسمى frames ) فارغ حاليًا. لذا فإن نظام التشغيل يتخلى عن وحدة المعالجة المركزية ، ويسمح لبرنامج تشغيل الجهاز بالوصول إلى القرص وجلب الصفحة لا. 4 لهذه العملية (في الأساس جزء ذاكرة من البرنامج على القرص الذي تتراوح عناوينه من 32 إلى 39 ). عند وصولها ، يقوم نظام التشغيل بتخصيص الصفحة في مكان ما في ذاكرة الوصول العشوائي (RAM) ، على سبيل المثال الإطار الأول نفسه ، ويحيط page table لهذه العملية علما بأن الصفحة 4 بالتخطيط لإطار 0 في ذاكرة الوصول العشوائي. الآن البيانات هناك في النهاية في الذاكرة الفعلية. يستعلم نظام التشغيل مرة أخرى عن جدول الصفحات للصفوف (4,3) ، 3 (4,3) ، وفي هذه المرة ، يقول جدول الصفحات أن الصفحة 4 تم تعيينها بالفعل إلى الإطار 0 في ذاكرة الوصول العشوائي. لذا فإن نظام التشغيل ببساطة يذهب إلى الإطار 0 في ذاكرة الوصول العشوائي ، يصل إلى البيانات عند الإزاحة 3 في ذلك الإطار (خذ لحظة لفهم ذلك. يتم نقل page بأكملها ، التي تم جلبها من القرص ، إلى frame . مهما كان إزاحة كان موقع الذاكرة الفردية في صفحة ما ، سيكون هو نفسه في الإطار كذلك ، حيث أن وحدة الذاكرة لا تزال موجودة في نفس المكان / frame ، في نفس المكان نسبيًا!) ، وتقوم بإرجاع البيانات! لأنه لم يتم العثور على البيانات في الذاكرة عند أول طلب بحث بذاته ، ولكن بدلاً من ذلك تم جلبه من القرص ليتم تحميله في الذاكرة ، وهو يمثل ملكة جمال .

غرامة. الآن افترض ، يتم الوصول إلى الذاكرة لموقع 28 . يتلخص إلى (3,4) . Page table الآن على إدخال واحد فقط ، تعيين صفحة 4 إلى إطار 0 . هذا هو مرة أخرى ملكة جمال ، العملية تتخلى عن وحدة المعالجة المركزية ، برنامج تشغيل الجهاز يجلب الصفحة من القرص ، عملية استعادة السيطرة على وحدة المعالجة المركزية مرة أخرى ، ويتم تحديث page table . قل الآن يتم تعيين الصفحة 3 إلى الإطار 1 في ذاكرة الوصول العشوائي. لذلك (3,4) يصبح (1,4) ، ويتم إرجاع البيانات في هذا الموقع في ذاكرة الوصول العشوائي. جيد. بهذه الطريقة ، افترض أن الوصول إلى الذاكرة التالية هو لموقع 8 ، والذي يترجم إلى (1,0) . الصفحة 1 ليست في الذاكرة بعد ، يتم تكرار نفس الإجراء ، ويتم تخصيص page في الإطار 2 في ذاكرة الوصول العشوائي. الآن تبدو عملية RAM- عملية مثل الصورة أعلاه. في هذه المرحلة ، يتم ملء ذاكرة الوصول العشوائي (RAM) ، التي كانت تحتوي على 24 وحدة فقط من الذاكرة. لنفترض أن طلب الوصول إلى الذاكرة التالي لهذه العملية هو من العنوان 30 . فإنه يشير إلى (3,6) ، 6 (3,6) ، page table يقول أن الصفحة 3 في ذاكرة الوصول العشوائي ، وأنه خرائط لإطار 1 . ياي! لذلك يتم جلب البيانات من موقع ذاكرة الوصول العشوائي (1,6) ، وعاد. هذا يشكل ضربة ، كما يمكن الحصول على البيانات المطلوبة مباشرة من ذاكرة الوصول العشوائي ، وبالتالي تكون سريعة جدا. وبالمثل ، فإن طلبات الوصول القليلة التالية ، مثل المواقع 11 و 32 و 26 و 27 كلها نتائج ، أي أن البيانات التي تطلبها العملية موجودة مباشرة في ذاكرة الوصول العشوائي دون الحاجة إلى البحث في مكان آخر.

الآن افترض أن طلب الوصول إلى الذاكرة لموقع 3 يأتي. يتم ترجمته إلى (0,3) page table لهذه العملية ، والذي يحتوي حاليًا على 3 إدخالات ، للصفحات 1 و 3 و 4 أن هذه الصفحة ليست في الذاكرة. مثل الحالات السابقة ، يتم جلبها من القرص ، ومع ذلك ، على عكس الحالات السابقة ، تملأ ذاكرة الوصول العشوائي! اذا ما العمل الآن؟ ماذا نفعل الآن؟ هنا يكمن جمال الذاكرة الظاهرية ، يتم طرد إطار من ذاكرة الوصول العشوائي! (هناك عوامل مختلفة تحكم الإطار المطلوب طرده. قد يكون موقعًا لـ LRU ، حيث يتم إخلاء الإطار الذي تم الوصول إليه مؤخرًا لإجراء عملية. قد يكون أساسًا first-cum-first-evicted ، حيث يكون الإطار الذي تم تخصيصه منذ وقت طويل ، يتم طرده ، إلخ.) لذلك يتم إخلاء بعض الإطار. قل الإطار 1 (اختياره عشوائيًا). ومع ذلك ، يتم تعيين هذا frame إلى بعض page ! (في الوقت الحالي ، يتم تعيينها من خلال جدول الصفحات الخاص بنا وعملية واحدة فقط من الصفحة 4 ). لذلك يجب إخبار هذه العملية المأساوية بالأخبار المأساوية ، أن frame واحدًا ، ينتمي إليك من المؤسف ، سيتم طرده من ذاكرة الوصول العشوائي لإفساح المجال pages أخرى. يجب أن تضمن العملية تحديث page table بهذه المعلومات ، أي إزالة الإدخال الخاص بهذا الثنائي ذي الإطارين ، بحيث يتم تقديم طلب هذه page في المرة القادمة ، لم يعد في الذاكرة ، ويجب أن يتم جلبه من القرص. جيد. لذلك يتم استبعاد الإطار 1 ، ويتم جلب الصفحة 0 ووضعها هناك في ذاكرة الوصول العشوائي ، وإزالة إدخال الصفحة 4 واستبدالها بتعيين الصفحة 0 إلى نفس الإطار 1 . حتى الآن ، يبدو تصميمنا كهذا (لاحظ تغير اللون في frame الثاني على الجانب الأيمن):

رأى ماذا حدث للتو؟ كان على هذه العملية أن تنمو وتحتاج إلى مساحة أكبر من ذاكرة الوصول العشوائي المتاحة ، ولكن بخلاف السيناريو السابق الذي كان يجب أن تتحرك فيه كل عملية في ذاكرة الوصول العشوائي (RAM) لاستيعاب عملية متنامية ، فقد حدث هنا استبدال page واحدة فقط! وقد أصبح هذا ممكنا من خلال حقيقة أن الذاكرة لعملية لم تعد بحاجة إلى أن تكون متجاورة ، يمكن أن يقيم في أماكن مختلفة في قطع ، ونظام التشغيل يحافظ على المعلومات إلى أين هم ، وعند الاقتضاء ، يتم استجوابهم بشكل مناسب. ملاحظة: قد تفكر ، هاه ، ماذا إذا كانت في معظم الأوقات هي miss ، ويجب تحميل البيانات باستمرار من القرص إلى الذاكرة؟ نعم ، من الناحية النظرية ، هذا ممكن ، ولكن معظم المجمعين مصممون بطريقة تتبع locality of reference ، أي إذا تم استخدام بيانات من موقع ذاكرة معين ، فإن البيانات التالية ستكون موجودة في مكان قريب جدًا ، ربما من نفس page ، page التي تم تحميلها فقط في الذاكرة. نتيجة لذلك ، سيحدث الانقطاع التالي بعد بعض الوقت ، سيتم تلبية معظم متطلبات الذاكرة القادمة من الصفحة التي تم جلبها للتو ، أو الصفحات الموجودة بالفعل في الذاكرة التي تم استخدامها مؤخرًا. يسمح لنا نفس المبدأ بالضبط بإخلاء page الأقل استخدامًا مؤخرًا ، مع منطق أن ما لم يتم استخدامه لفترة من الوقت ، لا يُحتمل استخدامه في بعض الوقت أيضًا. ومع ذلك ، فليس الأمر كذلك دائمًا ، وفي حالات استثنائية ، نعم ، قد يعاني الأداء. المزيد حول هذا الموضوع في وقت لاحق.

حل المشكلة 4: يمكن أن تنمو العمليات الآن بسهولة ، إذا واجهت مشكلة الفضاء ، كل ما يتطلبه الأمر هو إجراء استبدال بسيط page ، دون تحريك أي عملية أخرى.

حل لمشكلة 1: يمكن لعملية الوصول إلى ذاكرة غير محدودة. عند الحاجة إلى ذاكرة أكثر من المتاح ، يتم استخدام القرص كنسخة احتياطية ، ويتم تحميل البيانات الجديدة المطلوبة في الذاكرة من القرص ، ويتم نقل frame البيانات (أو page ) الأقل استخدامًا حديثًا إلى القرص. هذا يمكن أن يستمر بشكل لا نهائي ، وبما أن مساحة القرص رخيصة وغير محدودة فعليًا ، فإنه يعطي وهمًا لذاكرة غير محدودة. سبب آخر لاسم Virtual Memory ، يعطيك وهم الذاكرة التي ليست متوفرة حقًا!

رائع. في وقت سابق كنا نواجه مشكلة حيث أنه على الرغم من أن العملية تقل في الحجم ، فإن المساحة الفارغة يصعب استعادتها من خلال عمليات أخرى (لأنها تتطلب ضغطًا مكلفًا). الآن أصبح الأمر سهلاً ، عندما تصبح العملية أصغر حجمًا ، لم يعد يتم استخدام العديد من pages ، لذلك عندما تحتاج العمليات الأخرى إلى المزيد من الذاكرة ، تقوم عملية الإخلاء البسيطة التي تعتمد على LRU تلقائيًا بإخفاء تلك pages الأقل استخدامًا من ذاكرة الوصول العشوائي ، واستبدالها بالذاكرة. صفحات جديدة من العمليات الأخرى (وبالطبع تحديث page tables لجميع هذه العمليات وكذلك العملية الأصلية التي تتطلب الآن مساحة أقل) ، كل هذه دون أي عملية ضغط مكلفة!

حل لمشكلة 3: كلما اختفت العمليات من حيث الحجم ، ستكون frames في ذاكرة الوصول العشوائي أقل استخدامًا ، لذلك يمكن لطرد LRU بسيط طرد هذه الصفحات واستبدالها pages التي تتطلبها العمليات الجديدة ، وبالتالي تجنب Internal Fragmentation دون الحاجة إلى compaction .

أما بالنسبة للمشكلة 2 ، تأخذ لحظة لفهم هذا ، يتم إزالة السيناريو نفسه تماما! ليست هناك حاجة لتحريك عملية لاستيعاب عملية جديدة ، لأنه الآن لا تحتاج العملية بأكملها للاحتواء في وقت واحد ، تحتاج فقط صفحات معينة منها إلى احتواء مخصص ، يحدث ذلك من خلال طرد frames من ذاكرة الوصول العشوائي. كل شيء يحدث في وحدات من pages ، وبالتالي لا يوجد مفهوم hole الآن ، وبالتالي لا شك في أي شيء يتحرك! قد يكون 10 pages لنقلها بسبب هذا الشرط الجديد ، وهناك الآلاف من pages التي لم يتم المساس بها. في حين ، في وقت سابق ، كان لا بد من نقل جميع العمليات (كل جزء منها)!

حل المشكلة 2: لاستيعاب عملية جديدة ، يجب إخراج البيانات من الأجزاء الأقل استخدامًا في العمليات الأخرى على النحو المطلوب ، وهذا يحدث في وحدات ذات حجم ثابت تسمى pages . وبالتالي لا يوجد أي احتمال hole أو External Fragmentation مع هذا النظام.

الآن عندما تحتاج العملية إلى إجراء بعض عمليات الإدخال / الإخراج ، يمكن أن تتخلى عن CPU بسهولة! نظام التشغيل ببساطة يفرغ جميع pages من ذاكرة الوصول العشوائي (ربما تخزينها في بعض ذاكرة التخزين المؤقت) في حين أن عمليات جديدة تشغل ذاكرة الوصول العشوائي في غضون ذلك. عند الانتهاء من عملية الإدخال / الإخراج ، يقوم نظام التشغيل ببساطة باستعادة تلك pages إلى ذاكرة الوصول العشوائي (بالطبع عن طريق استبدال pages من بعض العمليات الأخرى ، قد يكون من تلك التي حلت محل العملية الأصلية ، أو قد تكون من بعض التي تحتاج إلى القيام بها بنفسها I / O الآن ، وبالتالي يمكن التخلي عن الذاكرة!)

حل لمشكلة 5: عندما تقوم إحدى العمليات بإجراء عمليات إدخال / إخراج ، يمكن أن تتخلى بسهولة عن استخدام ذاكرة الوصول العشوائي (RAM) ، والذي يمكن استخدامه في عمليات أخرى. هذا يؤدي إلى الاستخدام السليم لذاكرة الوصول العشوائي.

وبطبيعة الحال ، الآن لا توجد عملية الوصول إلى ذاكرة الوصول العشوائي مباشرة. تقوم كل عملية بالوصول إلى موقع الذاكرة الظاهرية ، والذي يتم تعيينه إلى عنوان RAM فعلي ويتم الاحتفاظ به بواسطة page-table هذه العملية. ويُعد نظام التشغيل مدعومًا بنظام التشغيل ، ويتيح نظام التشغيل لهذه العملية معرفة الإطار الفارغ بحيث يمكن تركيب صفحة جديدة لعملية ما هناك. بما أن هذا التخصيص للذاكرة يخضع لإشراف نظام التشغيل نفسه ، فيمكنه بسهولة ضمان عدم تعدي أي عملية على محتويات عملية أخرى من خلال تخصيص الإطارات الفارغة فقط من ذاكرة الوصول العشوائي ، أو عند التعدي على محتويات عملية أخرى في ذاكرة الوصول العشوائي ، الاتصال بالعملية لتحديثه page-table .

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

لذا فإن paging (من بين تقنيات أخرى) ، بالاقتران مع الذاكرة الظاهرية ، هو ما يبرهن على برامج التشغيل الحالية التي تعمل على أنظمة التشغيل OS! هذا يحرر مطور البرامج من القلق بشأن مقدار الذاكرة المتوفرة على جهاز المستخدم ، ومكان تخزين البيانات ، وكيفية منع العمليات الأخرى من إتلاف بيانات برنامجهم ، وما إلى ذلك. ومع ذلك ، فإنه بالطبع ليس دليلاً كاملًا. هناك عيوب:

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

لذا رجعت إلى OP ،

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

أين تقف هذه الذاكرة الظاهرية عندما يتم إحضار العملية (البرنامج) من القرص الصلب الخارجي إلى الذاكرة الرئيسية (الذاكرة الفعلية) للتنفيذ؟ - الذاكرة الظاهرية لا تقف في أي مكان في حد ذاتها ، بل هي تجريد ، دائمًا ، عندما يتم تمهيد البرنامج / العملية / البرنامج ، يتم إنشاء جدول صفحات جديد له ، ويحتوي على التعيين من العناوين spat out by that عملية إلى العنوان الفعلي الفعلي في ذاكرة الوصول العشوائي. بما أن العناوين التي تبثها العملية ليست عناوين حقيقية ، فهي في الواقع ، ما يمكنك قوله ، the virtual memory .

من يهتم بالذاكرة الظاهرية وما حجم الذاكرة الظاهرية؟ - يتم الاعتناء بها ، جنبًا إلى جنب ، ونظام التشغيل والبرنامج. تخيل وظيفة في التعليمات البرمجية الخاصة بك (التي تم تجميعها في نهاية المطاف وجعلها في الملف التنفيذي الذي أنتج العملية) التي تحتوي على متغير محلي - int i . عند تنفيذ التعليمات البرمجية ، أحصل على عنوان ذاكرة داخل كدسة الدالة. يتم تخزين هذه الوظيفة نفسها ككائن في مكان آخر. هذه العناوين هي مترجم ولدت (المترجم الذي جمع التعليمات البرمجية الخاصة بك في الملف التنفيذي) - عناوين افتراضية. عندما يتم التنفيذ ، يجب أن أقيم في مكان ما في العنوان الفعلي الفعلي لمدة تلك الوظيفة على الأقل (ما لم يكن متغيرًا ثابتًا!) ، لذلك يقوم نظام التشغيل بتعيين عنوان المحول الظاهري لـ i في عنوان فعلي فعلي ، لذلك كلما كان ذلك ، هذه الوظيفة ، تتطلب بعض التعليمات البرمجية قيمة i ، ويمكن لهذه العملية الاستعلام عن نظام التشغيل لهذا العنوان الظاهري ، ويمكن لنظام التشغيل بدوره الاستعلام عن العنوان الفعلي للقيمة المخزنة ، وإعادته.

لنفترض إذا كان حجم ذاكرة الوصول العشوائي هو 4 غيغابايت (أي 2 = 32-1 مساحة العناوين) ما هو حجم الذاكرة الظاهرية؟ - حجم ذاكرة الوصول العشوائي لا يرتبط بحجم الذاكرة الظاهرية ، بل يعتمد على نظام التشغيل. على سبيل المثال ، في Windows 32 بت ، يكون 16 TB ، على 64 بت ويندوز ، 256 TB . وبالطبع ، يتم تحديدها أيضًا بحجم القرص ، حيث يتم تخزين الذاكرة احتياطياً.







debugging memory-leaks operating-system memory-management