سؤال

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

object target = null;
try {
    // Instantiate and use the target object.
    // Assume we know what we are doing: the contents of this try block
    // do in fact represent the entire desired lifetime of the COM object,
    // and we are releasing all RCWs in reverse order of acquisition.
} finally {
    if(target != null) {
        Marshal.FinalReleaseComObject(target);
        target = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}

ومع ذلك، فإن بعض الناس يدافعون عن القيام بجمع القمامة من قبل Marshal.FinalReleaseComObject, ، بعض بعد، والبعض الآخر ليس على الإطلاق. هل من الضروري حقا أن GC كل RCW يدويا، خاصة بعد أن تم بالفعل فصلها عن كائن COM الخاص بها؟

إلى ذهني، سيكون أكثر بساطة وأسهل لفصل RCW من كائن COM وترك RCW لتنتهي صلاحيته بشكل طبيعي:

object target = null;
try {
    // Same content as above.
} finally {
    if(target != null) {
        Marshal.FinalReleaseComObject(target);
    }
}

هل يكفي القيام بذلك؟

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

المحلول

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

هذا يترك السؤال الأكبر لماذا يدعو الناس إلى الدعوة GC.Collect() و WaitForPendingFinalizers()?

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

ملاحظة إضافية هي أن الإعداد target ل null عادة ما تكون غير ضرورية، وعلى وجه التحديد غير ضروري في نموذج التعليمات البرمجية الخاصة بك. إعداد الكائنات إلى لا شيء هو ممارسة شائعة ل VB6 لأنها تستخدم جامع القمامة القائم على العد المرجعي. المحول البرمجي ل C # ذكي بما فيه الكفاية (عند البناء للإصدار) لمعرفة ذلك target لا يمكن الوصول إليها بعد استخدامها الأخير ويمكن أن يكون GC'D، حتى قبل مغادرته النطاق. واستخدام آخر استخدام، أقصد آخر استخدام ممكن لذلك هناك حالات قد تحددها null. وبعد يمكنك أن ترى هذا بنفسك مع الرمز أدناه:

   using System;
   class GCTest
   {
       ~GCTest() { Console.WriteLine("Finalized"); } 
       static void Main()
       {
           Console.WriteLine("hello");
           GCTest x = new GCTest();
           GC.Collect();
           GC.WaitForPendingFinalizers();
           Console.WriteLine("bye");
       }
   }

إذا قمت ببناء الإصدار (على سبيل المثال، CSC Gctest.cs)، فسيتم طباعة "النهائي" بين "Hello" و "وداعا". إذا قمت بإنشاء تصحيح (على سبيل المثال، CSC / Debug GCTEST.CS)، "سيتم الانتهاء منها" طباعة بعد "وداعا" في حين الإعداد x إلى null قبل Collect() سيكون "ثابت" ذلك.

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