如何修复由ContextMenuStrip引用的对象导致的内存泄漏 [英] How do I fix a memory leak caused by an object referenced by a ContextMenuStrip

查看:109
本文介绍了如何修复由ContextMenuStrip引用的对象导致的内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have used dotMemory to locate a memory leak. The object I want gone is referenced by an event handler through a ToolStripMenuItem and ContextMenuStrip. The object contains these properties:

    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方法以删除处理程序,但这没用.

I have simplified the code, the popup menu has about a dozen menu items, which all seem to be holding on to this object after I use the popup menu to delete the object. I have tried overriding the base delete method for the object to remove the handlers, but that did not work.

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

        base.delete();
    }

推荐答案

没有好的最小完整的代码示例,无法确定是什么问题,更不用说最好的解决方法了.那说…

Without a good, minimal, complete code example, it's impossible to know for certain what the problem is, never mind the best fix. That said…

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

Based on the tiny amount of code you've posted so far, it appears that you've misused the property feature in C#, and in doing so have obfuscated the code enough that you have been unable to recognize the bug. In particular, your ItemDelete property is creating a new object every time you call it, which is a horrible way to implement a getter of this kind. For the code to work correctly, you'd have to be careful to only ever call that property getter once, and manually cache the result somewhere else.

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

Creating a new object in a property getter isn't inherently bad, but it should be done only if that object will be cached by the property getter itself and reused for subsequent calls, or if that object is semantically a simple value (preferably an actual value type, but a simple, ummutable reference type would be fine too), where a newly created object is functionally identical to any previously created object (i.e. they can be used interchangeably without affecting the correctness of the code).

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

Given the above, it is possible that you would find the following alternative a useful way to fix the problem:

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的调用中,它将返回在第一次调用中创建的对象.

This will defer creation of the ToolStripMenuItem object until the first time that the property getter is called, but will on subsequent calls to the getter return that object created on the first call.

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

In this way, you will ensure that when you execute the statement ItemDelete.Click -= ItemDelete_Click; later, you are actually removing the event handler from the original object, rather than some new object you created at that time.

这篇关于如何修复由ContextMenuStrip引用的对象导致的内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆