小内存泄漏

时间:2014-06-01 17:26:20

标签: c# memory-leaks visual-studio-2013

新线程,委托和垃圾回收。

我在Visual Studio 2013中有一个C#程序,它在后台线程上运行循环,以不断更新主线程中表单上的控件。在循环运行时(并且仅在循环运行时),性能监视器显示该程序的私有字节数小而稳定地增加。

当后台线程停止并加入时,私有字节用法没有减少,但它不再增加。这个程序需要在循环线程中运行很长时间,因此在数小时/天之后,一个小的泄漏可能会成为一个问题。

我可以在循环中注释掉它要求更新方法的行;这成功地解决了这个问题。我在做什么来防止垃圾收集?

P.S。:如果你指的是一个查看堆的程序,请给我一步一步说明如何安装和使用它。我最近有点倦怠,到目前为止我在网上看到的对我的大脑来说还不够明显。

    private IAsyncResult iar;  // Store the IAsyncResult to check for completion the next time I call it.

    public delegate void Assisted_UpdateTimer(int totalSeconds, int secondsElapsed, int secondsRemaining);
    public void UpdateTimer(int totalSeconds, int secondsElapsed, int secondsRemaining)
    {
        if (this.InvokeRequired || pbTimeBar.InvokeRequired)  // If we need to be threadsafe
        {
            if (iar != null)  // If we've invoked something before
            {
                if (iar.IsCompleted)  // If the last thing we invoked has completed
                {
                    this.EndInvoke(iar);
                    Assisted_UpdateTimer _delegate = new Assisted_UpdateTimer(UpdateTimer);
                    iar = this.BeginInvoke(_delegate, totalSeconds, secondsElapsed, secondsRemaining);
                }
            }
            else  // Invoke for the first time
            {
                Assisted_UpdateTimer _delegate = new Assisted_UpdateTimer(UpdateTimer);
                iar = this.BeginInvoke(_delegate, totalSeconds, secondsElapsed, secondsRemaining);
            }
        }
        else  // The actual method code
        {
            TimeSpan timeElapsed = new TimeSpan(0, 0, secondsElapsed);
            TimeSpan timeRemaining = new TimeSpan(0, 0, secondsRemaining);
            int percent = (int)(((double)secondsElapsed / (double)totalSeconds) * 100);

            if (pbTimeBar.Maximum != totalSeconds) pbTimeBar.Maximum = totalSeconds;
            if (secondsElapsed >= 0) pbTimeBar.Value = secondsElapsed;  // pbTimeBar is a progress bar

            // Add text to progress bar
            pbTimeBar.CreateGraphics().DrawString(percent + "%", new Font("Arial", (float)8.25, FontStyle.Regular), new SolidBrush(Color.FromArgb(255, 0, 0, 0)), new PointF(pbTimeBar.Width / 2 - 10, pbTimeBar.Height / 2 - 7));

            labElapsed.Text = string.Format("{0:00}:{1:00}:{2:00} Elapsed", timeElapsed.Hours, timeElapsed.Minutes, timeElapsed.Seconds);
            labRemaining.Text = string.Format("Remaining {0:00}:{1:00}:{2:00}", timeRemaining.Hours, timeRemaining.Minutes, timeRemaining.Seconds);

            trayIcon.Text = string.Format("Toast Timer\nRemaining: {0:00}:{1:00}:{2:00}\nElapsed: {3}%", timeRemaining.Hours, timeRemaining.Minutes, timeRemaining.Seconds, percent);
        }
    }

1 个答案:

答案 0 :(得分:1)

我还没有检查过您的完整代码,但内存泄漏可能是强委托引用的可能输出。您会看到,当您将委托附加到对象事件时,除非手动删除委托引用,否则永远不会对该对象进行垃圾回收。以下是来自msdn的文档参考,以帮助您更好地理解场景并使用可能的解决方案 -

http://msdn.microsoft.com/en-us/library/aa970850(v=vs.110).aspx

  

侦听事件可能会导致内存泄漏。侦听事件的典型技术是使用特定于语言的语法将处理程序附加到源上的事件。例如,在C#中,该语法为:source.SomeEvent + = new SomeEventHandler(MyEventHandler)。

对于问题的最后一部分 - 我通常使用 Ant Profiler 进行内存测试。它不是免费的,但试用版通常有效并且给你足够的时间来解决问题。

http://www.red-gate.com/products/dotnet-development/ants-performance-profiler/

http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/

评论:我猜测重复调用UpdateTimer如果在每次调用中附加新代理,可能会造成内存泄漏。