繁体   English   中英

如何修复由ContextMenuStrip引用的对象导致的内存泄漏

[英]How do I fix a memory leak caused by an object referenced by a ContextMenuStrip

我已经使用dotMemory来定位内存泄漏。 事件处理程序通过ToolStripMenuItem和ContextMenuStrip引用了我想要的对象。 该对象包含以下属性:

    public override ContextMenuStrip PopupMenu
    {
        get
        {
            ContextMenuStrip myPopup = new ContextMenuStrip();
            myPopup.Items.Add(ItemDelete);
            return myPopup;
        }
    }

    public ToolStripMenuItem ItemDelete
    {
        get
        {
            ToolStripMenuItem itemDelete = new ToolStripMenuItem("Delete " + name);
            itemDelete.Enabled = Deletable;
            itemDelete.Image = Properties.Resources.del;
            itemDelete.Click += ItemDelete_Click;
            return itemDelete;
        }
    }

我简化了代码,弹出菜单中有大约十二个菜单项,在我使用弹出菜单删除对象后,所有这些菜单项似乎都保留在该对象上。 我尝试覆盖该对象的基本delete方法以删除处理程序,但这没有用。

    public override void delete()
    {
        if (PopupMenu != null)
        {
            ItemDelete.Click -= ItemDelete_Click;
        }

        base.delete();
    }

没有一个好的, 最小的完整的代码示例 ,就不可能确定是什么问题,更不用说最好的解决方案了。 那说...

根据到目前为止您已发布的少量代码,您似乎已经滥用了C#中的属性功能,并且这样做使代码变得模糊不清,导致您无法识别该错误。 特别是,您的ItemDelete属性每次调用时都会创建一个新对象,这是实现此类getter的一种可怕方法。 为了使代码正常工作,您必须注意只调用该属性getter一次,然后将结果手动缓存到其他位置。

在属性获取器中创建一个新对象并不是天生的坏事,但是只有当该对象将由属性获取器自身缓存并重新用于后续调用时,或者该对象在语义上是一个简单值(最好是实际值)时,才应执行此操作值类型,但也可以使用简单的,全变的引用类型),其中新创建的对象在功能上与任何先前创建的对象相同(即,它们可以互换使用而不会影响代码的正确性)。

鉴于上述情况 ,您可能会发现以下替代方法是解决问题的有用方法:

private Lazy<ToolStripMenuItem> _itemDelete =
    new Lazy<ToolStripMenuItem>(() => _CreateItemDelete());

private ToolStripMenuItem _CreateItemDelete()
{
    ToolStripMenuItem itemDelete = new ToolStripMenuItem("Delete " + name);
    itemDelete.Enabled = Deletable;
    itemDelete.Image = Properties.Resources.del;
    itemDelete.Click += ItemDelete_Click;
    return itemDelete;
}

public ToolStripMenuItem ItemDelete
{
    get
    {
        return _itemDelete.Value;
    }
}

这将延迟ToolStripMenuItem对象的创建,直到第一次调用属性getter时,但是在随后的对该getter的调用中,它将返回在第一次调用中创建的对象。

这样,您将确保执行语句ItemDelete.Click -= ItemDelete_Click; 稍后,您实际上是从原始对象中删除事件处理程序,而不是从那时创建的某些新对象中删除事件处理程序。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM