【问题标题】:C# BackgroundWorker eats memory on restartC# BackgroundWorker 在重启时吃掉内存
【发布时间】:2018-07-20 23:46:53
【问题描述】:

我用下面的代码创建了一个空Form来测试不断重启后台worker的性能;

        public Form1()
        {
            InitializeComponent();

            BackgroundWorker bw = new BackgroundWorker();
            // Do work on Background thread
            bw.DoWork += DoWork_WorkerThread;
            bw.RunWorkerAsync();
            // Return to UI thread and Restart the worker
            bw.RunWorkerCompleted += DoWork_WorkerThreadCompleted;
        }

        private void DoWork_WorkerThread(object sender, DoWorkEventArgs e)
        {
            System.Threading.Thread.Sleep(100);
            //GC.Collect();
        }

        private void DoWork_WorkerThreadCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // Restart the worker.
            // We can verify its the background worker because commenting this out relieves the issue.
            ((BackgroundWorker)sender).RunWorkerAsync();
        }

您可以在任务管理器中看到,每次从DoWork_WorkerThreadCompleted 重新启动worker 时,内存都会跳跃。

我注意到,如果我将GC.Collect() 扔进工作线程,问题就会消失。我是否错误地重新启动了工作程序,或者有没有办法确保在不调用 GC.Collect() 的情况下处理后台线程?

感谢您的宝贵时间。

【问题讨论】:

  • 你知道 GC 不会在 IDisposable 对象上调用 .Dispose() 吗?
  • 旁注:您可能应该在调用 RunWorkerAsync 之前分配 RunWorkerCompleted 事件。
  • 另外,启动一个线程会消耗至少 1MB 的 RAM,因为它会创建一个运行时堆栈。
  • 感谢大家的回复和对已完成活动的良好呼吁。泰

标签: c# multithreading winforms backgroundworker


【解决方案1】:

只有少数用例需要显式调用 GC。仅仅因为重复动作时内存增加并不一定意味着存在内存泄漏。 .NET 仅在真正需要时才释放内存,例如内存压力很高的时候。致电GC.Collect 只会强制解决问题。

注释掉 worker start 并不能真正证明什么。虽然是的,在这种情况下您已经阻止了内存增加,但您也消除了在工作人员运行完成并允许有足够的时间或事件再次释放内存时释放内存的可能性。 你永远无法准确地预测 GC 何时会发生。 打电话GC.Collect 是不行的。

你可以换一种方式来思考这个问题。想象一下分配一个你知道的对象会使用合理数量的 RAM。

void DoSomething()
{
    var ob = new MyObjectRequiringReasonableAmountOfRam();
    // 'ob' goes out of scope and is now a candidate for GC at some time or other
}

现在调用此方法,对象被分配并超出范围,是的内存可能会增加,但现在认为存在内存泄漏还为时过早。当然,注释掉代码会消除“泄漏”的症状,但它也会删除功能,就像注释掉你的工作线程一样。

现在,如果除了调用上述方法之外,我还调用:

void DoSomethingSlightlyMoreDrastic()
{
    var ob = new MyObjectRequiringALargerAmountOfRam();
    // 'ob' goes out of scope and is now a candidate for GC at some time or other
}

....NET 看到此分配需要更多内存并考虑系统上的所有其他因素,例如您的进程分配了多少内存;所有其他进程的内存;您计算机中的 RAM 以及 GC 的工作原理,您的第一个对象完全有可能在此时被 GC。

【讨论】:

  • 感谢您的解释。在这种情况下,我不应该看到垃圾收集器启动并平衡或降低内存使用量吗?似乎在这个例子中增加是恒定的
  • @clamchoda 欢迎您。也许它正在发挥作用而您不知道?在调试器中运行它并确保 Diagnostic Tools 窗口已打开。 GC 事件通常以黄色显示。 blogs.msdn.microsoft.com/visualstudio/2016/02/15/…
猜你喜欢
  • 1970-01-01
  • 2021-03-24
  • 1970-01-01
  • 2020-05-20
  • 1970-01-01
  • 1970-01-01
  • 2011-07-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多