ios - فهم الاحتفاظ دورة في العمق




objective-c memory-management (5)

Retain Cycle هي الشرط عندما يحتفظ جسمان بالإشارة إلى بعضهما الآخر ويتم الاحتفاظ بهما ، يقوم بإنشاء دورة الاحتفاظ حيث يحاول كل منهما الاحتفاظ ببعضهما البعض ، مما يجعل من المستحيل تحريره.

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

هناك نوعان من الحلول الممكنة:

1) استخدام مؤشر ضعيف لأولياء الأمور ، أي أن الطفل يجب أن يستخدم إشارة ضعيفة للوالد ، والتي لا يتم الاحتفاظ بها.

2) استخدام أساليب "إغلاق" لكسر دورات الاحتفاظ.

http://www.cocoawithlove.com/2009/07/rules-to-avoid-retain-cycles.html

دعنا نقول أن لدينا ثلاثة أشياء: الأجداد والأب والطفل. يحتفظ الجدين بالوالد ، ويحتفظ الوالد بالطفل ويحتفظ الطفل بالوالد. يقوم الجدين بإطلاق سراح الوالد.

ماذا سيحدث في هذه الحالة؟


دورة retain هي حلقة تحدث عندما يحتفظ الكائن A بالكائن "ب" ، بينما يحتفظ الكائن "ب" بالكائن "أ". وفي هذه الحالة ، إذا تم إطلاق أي كائن:

  • لن يتم إلغاء تخصيص الكائن "أ" نظرًا لأن الكائن "ب" يحمل مرجعًا له (يحتفظ بالعد> 0).
  • لن يتم أبداً إلغاء تخصيص الكائن B طالما أن الكائن A له إشارة إليه (يحتفظ بالعد> 0).
  • ولكن لن يتم أبداً إلغاء تمييز الكائن "أ" لأن "كائن" ب "" يحتفظ بإشارة إليه (يحتفظ بحسابه> 0).
  • حتى اللانهاية

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


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

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


نظرًا لاحتفاظ كائن P بتعداد 1 ، عند إصداره ، فإن retainCount الخاص به يذهب إلى 0 ، ويتم استدعاء أسلوبه dealloc ؛ هذا بدوره يستدعي الإصدار على كائن C ، الذي ينتقل عده إلى 0 أيضًا. وتسمى طريقة dealloc.

سيتم تحرير كل من الكائنين P و C.

عندما يتم استدعاء طريقة Dealloc لكائن C ، يتم استدعاء إطلاق كائن GP ، ولكن نظرًا لأن GP يحمل عدد الاحتفاظ 2 ، يتم تقليل عدد الاحتفاظ إلى 1 ، ويستمر في التواجد.


في حالة بسيطة ، ضع في اعتبارك جهازي A و B حيث A ينشئ ويحتفظ ب. عندما يتم إنشاء A ، فإنه يخلق B. عندما يقوم أي شخص ينشئ A بإطلاقه أخيراً ، يتم احتجاز العد A إلى الصفر ويتم إلغاء تخصيصه. إذا كانت طريقة Dealloc الخاصة بـ A تطلق الإصدار B ، فإن عدد الإبقاء على B ينخفض ​​أيضًا إلى الصفر ويتم أيضًا إلغاء تخصيصه. [هذا يفترض أنه لم يحتفظ أي شخص آخر بـ A أو B ، لأنني أبقي الأمور بسيطة.]

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

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

في قضيتك A هو الوالد وباء طفل وكل من خلق A هو الجدين.





retain-cycle