【问题标题】:Memory leaks in InkEdit controlInkEdit 控件中的内存泄漏
【发布时间】:2020-08-29 08:50:09
【问题描述】:

如果没有内存泄漏,我无法销毁 InkEdit。 Dispose 方法有一点帮助,但仍然没有释放大量非托管资源。

            // Create 16 InkEdit components

            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    var ie = new InkEdit { Left = x * 50, Top = y * 50, Width = 40, Height = 40 };
                    panel1.Controls.Add(ie);
                }
            }

修改示例以正确处理所有控件。

            // 46 MiB of leaked RAM after every Create/Dispose iteration

            while (panel1.Controls.Count > 0)
            {
                var lastIndex = panel1.Controls.Count - 1;
                var control = panel1.Controls[lastIndex];
                panel1.Controls.RemoveAt(lastIndex);

                control.Dispose();
            }

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

使用 GC.Collect:

没有 GC.Collect:

完整样本: https://github.com/dermeister0/InkEditTest

【问题讨论】:

  • panel1.Controls.Clear(); 当然不会处理任何东西。你调用control.Dispose(); 的foreach 循环是错误的,你不能修改你正在迭代的集合,你不会处理所有控件。 清除 Controls 集合仍然是Controls.Clear()。使用向后的for 循环(从panel1.Controls.Count - 1 到0)。你可以在循环之后只调用GC.Collect(),它不会有太大的不同。
  • 我猜这不是泄漏。由于对未来对象实例分配的优化,GC 只是保持内存在使用中。处理和收集并不意味着releasing内存。
  • @aepot 该代码确实在泄漏:OP 没有处理那些控件(确实需要处理),因此内存使用量会不断增加。无论如何,代码只需要一点点修复(已经描述过)。
  • @Jimi 不,GC 将自动为所有 IDisposable 对象调用终结器。我希望该类即使内部有非托管资源也能正确实现。结果,不会有泄漏。无论如何,问题信息中提供的内存屏幕截图与泄漏无关。我知道某些 .NET 类在极少数情况下可能会泄漏,但这种情况很常见,不会导致真正的泄漏。我建议 OP 进一步了解 CLR 中的垃圾收集。
  • @aepot 技术上,这正是它所做的,也是它应该做的。

标签: c# winforms memory-leaks


【解决方案1】:

我使用SimpleHelpers.ObjectPool 包来重用控件。

SimpleHelpers.ObjectPool<InkEdit>.MaxCapacity = 16;
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                SimpleHelpers.ObjectPool<InkEdit>.Clear();

                components?.Dispose();
            }
            base.Dispose(disposing);
        }

        private void btnCreate_Click(object sender, EventArgs e)
        {
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    InkEdit ie = SimpleHelpers.ObjectPool<InkEdit>.Get(() => new InkEdit());

                    ie.Left = x * 50;
                    ie.Top = y * 50;
                    ie.Width = 40;
                    ie.Height = 40;

                    panel1.Controls.Add(ie);
                }
            }
        }

        private void btnDisposeAndClear_Click(object sender, EventArgs e)
        {
            for (int i = panel1.Controls.Count - 1; i >= 0; i--)
            {
                var control = panel1.Controls[i] as InkEdit;
                SimpleHelpers.ObjectPool<InkEdit>.Put(control);
            }
        }

【讨论】:

    猜你喜欢
    • 2021-12-06
    • 2013-08-02
    • 1970-01-01
    • 2013-12-29
    • 2016-06-09
    • 1970-01-01
    • 2016-02-26
    • 2013-01-27
    • 2012-07-30
    相关资源
    最近更新 更多