1

我的应用程序中有内存泄漏,我找不到真正的来源。在一个名为的控件中有这行代码DataTableEditor

refreshButton.DataBindings.Add("Enabled", asyncSqlResultsViewer, "CanRefresh", true, DataSourceUpdateMode.Never);

asyncSqlResultsVewer只是一个DataGridView显示数据的用户控件。用于异步加载数据,但现在不再加载。该DataTableEditor控件是另一个包含AsyncSqlResultsVewer. 泄漏似乎与此有关,因为它显示PropertyDescriptor为保持对象活动的路径的一部分:

.net 内存分析器屏幕截图

我是使用 .NET Memory Profiler 的新手,但问题是,删除上面的行可以消除泄漏。删除绑定DataBindings.Remove也可以修复泄漏。但是,这应该发生吗?被asyncSqlResultsVewer处置并且据我所知与 一起被取消引用DataTableEditor,因此只要没有其他人引用它们中的任何一个(对吗?),它们中的每个引用都不应该让它们继续存在。我仍然可以删除绑定以防万一或作为黑客攻击,但我希望有人帮助我找出泄漏的真正原因是什么。

如果您怀疑这是实际的内存泄漏,应用程序会在打开和关闭几个DataTableEditor显示大量数据的 s 后崩溃。此外,分析器告诉我该对象已被处置,但仍有对其的引用。

如果有任何其他信息可以帮助您帮助我解决这个问题,请告诉我。

编辑:我想我知道泄漏可能来自哪里。refreshButton上面是这个类的一个实例:

public class ToolStripBindableButton : ToolStripButton, IBindableComponent, INotifyPropertyChanged
{
    private ControlBindingsCollection dataBindings;

    private BindingContext bindingContext;

    public ControlBindingsCollection DataBindings
    {
        get
        {
            if (dataBindings == null) dataBindings = new ControlBindingsCollection(this);
            return dataBindings;
        }
    }

    public BindingContext BindingContext
    {
        get
        {
            if (bindingContext == null) bindingContext = new BindingContext();
            return bindingContext;
        }
        set { bindingContext = value; }
    }

    public override Image Image
    {
        get { return base.Image; }
        set { SetImage(value); }
    }

    private void SetImage(Image value)
    {
        if (base.Image != value)
        {
            base.Image = value;
            OnPropertyChanged(new PropertyChangedEventArgs("Image"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null) PropertyChanged(this, e);
    }
}

添加Dispose覆盖并dataBindings.Clear()修复泄漏。这是我应该做的事情还是泄漏的真正原因仍在其他地方?

4

1 回答 1

2

我相信您已经自己回答了内存泄漏问题。

在我看来,泄漏的来源似乎很可能是刷新按钮(的实例ToolStripBindableButton)。

ToolStripButton.Dispose()被调用时,它知道如何清理/释放所有需要的对象。但是它无法知道你是如何扩展类的,因此它不能帮助你清理。

我会期望ControlBindingsCollectionBindingContext继承IDisposable,从而清楚地表明需要进行清理。

protected override void Dispose(bool disposing)
{
  base.Dispose(disposing);

  if (disposing && dataBindings != null)
  {
    dataBindings.Clear();
  }
  dataBindings = null;
  dindingContext = null;
  PropertyChanged = null;
}

很难说你是否找到了问题的根源,但我会密切关注任何未以某种方式处理/释放/杀死的事件。

还要密切关注表单上的组件。Theise 只有在使用 IContainer 实例创建时才会自动处理,并且 WinForms 设计者可以选择不这样做。

于 2013-02-14T07:03:54.373 回答