C# 从System.Threading.Timer在UI中调用时如何避免泄漏句柄?

C# 从System.Threading.Timer在UI中调用时如何避免泄漏句柄?,c#,.net,winforms,timer,handle-leak,C#,.net,Winforms,Timer,Handle Leak,在System.Threading.Timer的回调中调用winforms控件似乎会泄漏句柄,直到释放计时器为止。有人知道如何解决这个问题吗?我需要每秒轮询一个值,并相应地更新UI 我在一个测试项目中尝试了它,以确保这确实是泄漏的原因,原因如下: System.Threading.Timer timer; public Form1() { InitializeComponent(); timer = new System.Threading

在System.Threading.Timer的回调中调用winforms控件似乎会泄漏句柄,直到释放计时器为止。有人知道如何解决这个问题吗?我需要每秒轮询一个值,并相应地更新UI

我在一个测试项目中尝试了它,以确保这确实是泄漏的原因,原因如下:

    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任务管理器中观看,这将每秒泄漏2个句柄。

是否有某些原因使您无法在此处使用System.windows.Forms.Timer?如果计时器绑定到该表单,您甚至不需要调用。

有趣-这不是答案,但根据Andrei的评论,我认为这不会以相同的方式泄漏处理,但它确实以与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);
    }

Invoke的作用类似于BeginInvoke/EndInvoke对,它将消息发布到UI线程,创建句柄,并等待该句柄来确定调用的方法何时完成。正是这个句柄“泄漏”。您可以看到,这些都是未命名的事件,用于在应用程序运行时监视句柄

如果IASyncResult是可识别的,则处理该对象将负责清理句柄。事实并非如此,当垃圾收集器运行并调用IASyncResult对象的终结器时,句柄将被清除。您可以通过在每20次对DoStuff的调用后添加一个GC.Collect()看到这一点——句柄计数每20秒下降一次。当然,通过向GC.Collect()添加调用来“解决”问题是解决问题的错误方法;让垃圾收集器完成自己的工作


如果不需要调用同步,请使用BeginInvoke而不是Invoke,并且不要调用EndInvoke;最终结果将做同样的事情,但不会创建或“泄漏”句柄。

好的,我给了它多一点时间,它看起来实际上并没有泄漏句柄,这只是垃圾收集器的不确定性质。我把它撞到了每滴答10毫秒的高度,它会爬得很快,30秒后又会掉下来


在每一个回调中手动地定义GC.Cuffor()的理论(在实际项目中不做这件事,这只是为了测试,有很多文章说明为什么它是坏主意),句柄计数是稳定的。< /P>每一个C++遵守规则1:每一个新的都必须跟随删除!是的,我想知道这是如何工作的,在每个回调中放置一个委托似乎会导致创建句柄。这可能是一个没有清理的隔室封送问题吗?在实际代码中,计时器不在表单中,而是在演示者调用视图中。我试着换成System.Windows.Forms.Timer,但由于某种原因它没有启动,我也没有花太多时间试图找出原因,并认为这与它不在从控件派生的类中有关。我真的建议使用Windows.Forms.Timer(并不是说理解句柄泄漏也不好!)您在尝试计时器时是否在计时器上设置了Enabled属性?我看不出为什么它需要由从控件派生的类中的代码创建-首先,它怎么知道?我设置了一个间隔,给了Tick事件一个处理程序,并调用了start()但事件处理程序上的断点从未被命中。无论如何,看起来实际上没有句柄泄漏,垃圾回收器需要一段时间来处理它。请看我自己的答案。它不会运行,因为包含的线程是非泵送的。它需要由窗体拥有。我注意到它确实自行消失,因此我就这么说吧,不过谢谢你的解释。很好。谢谢你的详细回答。很高兴知道。