Memory Leak in C#

Is it ever possible in a managed system to leak memory when you make sure that all handles, things that implement IDispose are disposed?

Would there be cases where some variables are left out?


Event Handlers are a very common source of non-obvious memory leaks. If you subscribe to an event on object1 from object2, then do object2.Dispose() and pretend it doesn't exist (and drop out all references from your code), there is an implicit reference in object1's event that will prevent object2 from being garbage collected.

MyType object2 = new MyType();

// ...
object1.SomeEvent += object2.myEventHandler;
// ...

// Should call this
// object1.SomeEvent -= object2.myEventHandler;

object2.Dispose();

This is a common case of a leak - forgetting to easily unsubscribe from events. Of course, if object1 gets collected, object2 will get collected as well, but not until then.


I don't think C++ style memory leaks are possible. The garbage collector should account for those. It is possible to create a static object that aggregates object references even though the objects are never used again. Something like this:

public static class SomethingFactory
{
    private static List<Something> listOfSomethings = new List<Something>();

    public static Something CreateSomething()
    {
        var something = new Something();
        listOfSomethings.Add(something);
        return something;
    }
}

That's an obviously stupid example, but it would be the equivalent of a managed runtime memory leak.


As others have pointed out, as long as there's not an actual bug in the memory manager, classes that don't use unmanaged resources won't leak memory.

What you see in .NET is not memory leaks, but objects that never get disposed. An object won't get disposed as long as the garbage collector can find it on the object graph. So if any living object anywhere has a reference to the object, it won't get disposed.

Event registration is a good way to make this happen. If an object registers for an event, whatever it registered with has a reference to it, and even if you eliminate every other reference to the object, until it unregisters (or the object it registered with becomes unreachable) it will stay alive.

So you have to watch out for objects that register for static events without your knowledge. A nifty feature of the ToolStrip , for instance, is that if you change your display theme, it will automatically redisplay in the new theme. It accomplishes this nifty feature by registering for the static SystemEvents.UserPreferenceChanged event. When you change your Windows theme, the event gets raised, and all of the ToolStrip objects that are listening to the event get notified that there's a new theme.

Okay, so suppose you decide to throw away a ToolStrip on your form:

private void DiscardMyToolstrip()
{
    Controls.Remove("MyToolStrip");
}

You now have a ToolStrip that will never die. Even though it isn't on your form anymore, every time the user changes themes Windows will dutifully tell the otherwise-nonexistent ToolStrip about it. Every time the garbage collector runs, it thinks "I can't throw that object away, the UserPreferenceChanged event is using it."

That's not a memory leak. But it might as well be.

Things like this make a memory profiler invaluable. Run a memory profiler, and you'll say "that's odd, there seem to be ten thousand ToolStrip objects on the heap, even though there's only one on my form. How did this happen?"

Oh, and in case you're wondering why some people think property setters are evil: to get a ToolStrip to unregister from the UserPreferenceChanged event, set its Visible property to false .

链接地址: http://www.djcxy.com/p/57028.html

上一篇: 是否有良好的Valgrind替代Windows?

下一篇: 内存泄漏在C#中