سؤال

لقد كنت أقرأ لجمع القمامة البحث عن ميزات لتشمل في لغتي البرمجة وتواصل "مؤشرات ضعيفة". من هنا:

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

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

لم أسمع أبدا عن المؤشرات الضعيفة من قبل. أود أن أدعم العديد من الميزات في لغتي، ولكن في هذه الحالة لا أستطيع أن أفكر في حياة لي في حالة من المفيد. لماذا استخدام المرء مؤشر ضعيف؟

هل كانت مفيدة؟

المحلول

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

نصائح أخرى

واحد كبير حقا هو التخزين المؤقت. وبعد دعونا نفكر من خلال كيفية عمل ذاكرة التخزين المؤقت:

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

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

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

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

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

استخدمها عندما تريد الاحتفاظ بقائمة مخزنة مؤقتا من الكائنات ولكن لا تمنع هذه الكائنات من الحصول على القمامة التي تم جمعها إذا تمت مالك "حقيقي" للكائن به.

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

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

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

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

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

المؤشرات ضعيفة تبقي كل ما يحملها من أن تصبح شكل من أشكال "دعم الحياة" للكائن يشير المؤشر إلى.

قل أنه كان لديك فئة Viewport، وفصول 2 واجهة المستخدم، وطبقات القطعة. تريد أن تتحكم واجهة المستخدم الخاصة بك في عمر الحاجيات التي تنشئها، لذلك يبقي UI الخاص بك SharedPtrs على جميع الحاجيات التي يتحكم فيها. طالما كان كائن UI الخاص بك على قيد الحياة، فلن يتم جمع أي من الحاجيات من الحاجيات التي يتم جمعها من القمامة (بفضل SharedPtr).

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

إذا قمت بمرور عرض Viewport جميع الحاجيات كضعف، فما بمجرد حذف فئة UI، فلن يكون هناك المزيد من المشاركين في الحاجيات، لذلك سيكونون القمامة التي تم جمعها، فإن مراجع Viewport إلى الكائنات لن يحتفظ بها " دعم الحياة "، وهذا هو بالضبط ما تريد لأنك لا تستخدم حتى أن واجهة المستخدم بعد الآن، وأقل الحاجيات التي تم إنشاؤها.

الآن، ضع في اعتبارك أنك قد مرت بعرض SharedPointer، فأنت تحذف واجهة المستخدم، والحماجيات ليست القمامة التي تم جمعها! لماذا ا؟ نظرا لأن Viewport، الذي لا يزال على قيد الحياة لديه صفيف (متجه أو قائمة، أيا كان) مليء بالشرائط على الحاجيات. أصبح Viewport ساري المفعول شكلا من أشكال "دعم الحياة" بالنسبة لهم، على الرغم من أنك قد حذفت UI التي كانت تتحكم في الحاجيات على كائن UI آخر.

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

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

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

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

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

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

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

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

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

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

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

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top