كيفية تجنب تسرب المقابض عند استدعاء واجهة المستخدم من System.Threading.Timer؟

StackOverflow https://stackoverflow.com/questions/1603123

سؤال

يبدو الأمر وكأن استدعاء Invocation على عنصر تحكم winforms في رد اتصال من مقابض تسرب System.Threading.Timer حتى يتم التخلص من المؤقت.هل لدى أي شخص فكرة عن كيفية التغلب على هذا؟أحتاج إلى استطلاع قيمة كل ثانية وتحديث واجهة المستخدم وفقًا لذلك.

لقد قمت بتجربته في مشروع اختباري للتأكد من أن هذا هو سبب التسرب بالفعل، وهو ببساطة ما يلي:

    System.Threading.Timer timer;
    public Form1()
    {
        InitializeComponent();
        timer = new System.Threading.Timer(new System.Threading.TimerCallback(DoStuff), null, 0, 500);
    }
    void DoStuff(object o)
    {
        this.Invoke(new Action(() => this.Text = "hello world"));
    }

سيؤدي هذا إلى تسرب مقبضين في الثانية إذا شاهدت في مدير مهام Windows.

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

المحلول

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

إذا كان IASyncResult IDisposable، فإن التخلص من وجوه رعاية تنظيف مقبض. كما أنها ليست، مقابض الحصول على تنظيف عند تشغيل جامع القمامة ويدعو finalizer الكائن IASyncResult. يمكنك ان ترى هذا بإضافة الأسلوب GC.Collect () بعد كل 20 دعوات لDoStuff - عدد مقبض قطرات كل 20 ثانية. بطبيعة الحال، "حل" المشكلة عن طريق إضافة المكالمات إلى الأسلوب GC.Collect () هي الطريقة <م> خطأ لمعالجة هذه المسألة. السماح للجامع القمامة تقوم بعملها الخاصة.

إذا كنت لا <م> الحاجة نداء استدعاء ليكون متزامن، واستخدام BeginInvoke بدلا من استدعاء ولا تستدعي EndInvoke. فإن النتيجة النهائية تفعل نفس الشيء ولكن سيتم إنشاء أي مؤشرات أو "تسربت".

نصائح أخرى

هل هناك سبب لا يمكنك استخدام System.Windows.Forms.Timer هنا؟ إذا لا بد من توقيت لهذا النموذج أنك لن تحتاج حتى إلى الاحتجاج.

حسنًا، لقد أعطيتها المزيد من الوقت ويبدو أنها في الواقع لا تسبب تسريبًا للمقابض، إنها مجرد طبيعة غير محددة لجامع القمامة.لقد صدمتها بما يصل إلى 10 مللي ثانية لكل علامة، وسوف تصعد بسرعة كبيرة وبعد 30 ثانية سوف تنخفض مرة أخرى.

لتأكيد النظرية، قمت يدويًا باستدعاء GC.Collect() في كل رد اتصال (لا تفعل ذلك في المشاريع الحقيقية، كان هذا فقط للاختبار، فهناك العديد من المقالات حول سبب كونها فكرة سيئة) وكان عدد المقابض مستقرًا.

ومثيرة للاهتمام - وهذا ليس جوابا ولكن على أساس تعليق اندريه كان يمكن أن أفكر أن هذا لا تسرب يعالج بنفس الطريقة إلا أنه لا يعالج تسرب بمعدل نفسه OP ذكر

System.Threading.Timer timer;
    public Form2()
    {
        InitializeComponent();

    }

    private void UpdateFormTextCallback()
    {
        this.Text = "Hello World!";
    }

    private Action UpdateFormText;

    private void DoStuff(object value)
    {
        this.Invoke(UpdateFormText);
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        timer = new System.Threading.Timer(new TimerCallback(DoStuff), null, 0, 500);
        UpdateFormText = new Action(UpdateFormTextCallback);
    }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top