Event Handler Memory Leaks

by Chad 9. February 2010 06:18

Event handlers are a common cause of memory leaks in managed applications. It’s so easy to register an event handler, that sometimes we can forget what’s actually happening. There are three parties involved in eventing: the event source, a delegate, and the event sink.

The event source is the object that publishes notifications via an event. The event sink is the object that is interested in those notifications and knows how to respond to the event. The delegate is the object that enables the event source to communicate with the event sink.

Looking at the System.Delegateclass, we see that it has two properties: Target and Method. Target contains a reference to the event sink object and Method contains a MethodInfo object used to invoke the event handler method on the event sink object. When you use the C# statement eventSource.SomeEvent += new EventHandler(eventSink.SomeEventHandler); you are creating a new delegate with a reference to your event sink object and adding a reference to the delegate class to the event source object. The references look like this: event source > delegate > event sink.

The effect of this isn’t very visible when the lifetime of the event source and event sink are similar. However, when the event source lives much longer, say for the lifetime of the application, and the event sink only has a short lifetime, you can quickly leak memory because the event source will never release it’s reference to the event sink.

Consider this example

class View

{

    private string _name;

    public View(string name)

    {

        _name = name;

 

        // Register for CollectionChanged notifications; MASTER_COLLECTION

        // is static.

        Program.MASTER_COLLECTION.CollectionChanged +=

            new NotifyCollectionChangedEventHandler(

                masterCollection_CollectionChanged);

    }

 

    void masterCollection_CollectionChanged(object sender,

        NotifyCollectionChangedEventArgs e)

    {

        // Update view

        Console.WriteLine("{0}: {1} items.",

            _name,

            Program.MASTER_COLLECTION.Count);

    }

 

    ~View()

    {

        Console.WriteLine("View {0} Finalized.", _name);

    }

}

 

class Program

{

    public static readonly ObservableCollection<object> MASTER_COLLECTION

        = new ObservableCollection<object>();

 

    public void Run()

    {

        // Create two views

        View v1 = new View("v1");

        View v2 = new View("v2");

 

        // Raise CollectionChanged event

        MASTER_COLLECTION.Add(new object());

 

        // Release v1 & v2 references

        v1 = null;

        v2 = null;

 

        // Wait for Garbage collector to release memory

        GC.Collect();

        GC.WaitForPendingFinalizers();

 

        // Create v3

        View v3 = new View("v3");

 

        // Raise CollectionChanged event

        Console.WriteLine("We only expect v3 to be in memory.");

        MASTER_COLLECTION.Add(new object());

        v3 = null;

 

        // Wait for Garbage collector to release memory

        GC.Collect();

        GC.WaitForPendingFinalizers();

 

        Console.WriteLine("Example finished.");

        Console.ReadLine();

    }

 

 

    static void Main(string[] args)

    {

        Program p = new Program();

        p.Run();

    }

}

The output for this is:

v1: 1 items.
v2: 1 items.
We only expect v3 to be in memory.
v1: 2 items.
v2: 2 items.
v3: 2 items.
Example finished.
View v3 Finalized.
View v1 Finalized.
View v2 Finalized.

How to avoid this?
You need to keep this subtle problem in mind when designing your classes. To prevent these types of memory leaks, you’ll need to design mechanisms into your object’s lifecycle so that it can detach it’s event handlers. Detaching an event handler is as simple as using the –= operator. The difficult part is knowing when to detach. You can use the IDisposable pattern or expose a CleanUp() method or add lifecycle events to trigger the detach.

Tags: ,

.NET-Basics

Another Use for Extension Methods

by Chad 24. November 2009 11:55

I’m a big fan of Extension Methods and today I found another use for them while discussing the Managed Extensibility Framework with my friend Matt Lowrance. I previously thought that there was little reason to add extension methods to types that you control the source code for. The idea being that if you have access to the source code, it’s better to extend the type directly since you’ll have access to private state.

DiagramToday’s epiphany is that in a loosely coupled system, Extension Methods can be used to hide that loose coupling.  For example consider the diagram to the right. I have an ObjectContainer class that is unaware of my CustomObject class. Additionally, CustomObject may be completely unaware of ObjectContainer.

Using an extension method, I can call GetCustomObjects() on an instance of ObjectContainer and receive an array of CustomObject. With this syntax, it appears that the ObjectContainer is aware of CustomObject, but in reality it isn’t. The only type that is tightly coupled is the static ExtensionMethods class that must be aware of both types.

Tags: ,

.NET-Basics

Custom WPF ContextMenu

by Chad 6. November 2009 12:14

Recently, I wanted to add a custom tooltip to my WPF application. I wanted the tooltip to display some details about a record and provide buttons that could be clicked to perform some actions on that record. It turns out that this is a very simple thing to do, but because I started with the idea of a tooltip it was a difficult road to my final solution. It appears that several others on the internet have experienced the same situation as I did, so I decided to blog about it.

First Attempt

Starting with the ToolTip, I quickly found that as I moused over the rows, my custom tooltip would display with the buttons.  When I tried to click a button the tooltip would move to the next record in my list; effectively forcing me to chase the control around the screen. So I thought to myself, let’s try activating the tooltip on a right-click and preventing it from automatically closing. A quick search in my favorite search engine indicated that this was a misuse of the ToolTip control.

<!-- Source Code Reenactment: !!!THIS DOESN’T WORK!!! -->

<TextBlock.ToolTip>

    <ToolTip>

        <ToolTip.Template>

            <ControlTemplate>

                <Button>Do Something</Button>

            </ControlTemplate>

        </ToolTip.Template>

    </ToolTip>

</TextBlock.ToolTip>

Solution

With a little research, I found that the functionality that I was looking for came with the ContextMenu and Popup controls.  Both appeared that they’d solve my problem. Both allowed me to display content floating outside of the visual tree and both will accept focus. I ultimately decided to use the ContextMenu because it has built-in right-click support and will automatically hide itself when I click outside of it.

<TextBlock.ContextMenu>

    <ContextMenu>

        <ContextMenu.Template>

            <ControlTemplate>

                <Border Background="Black" CornerRadius="10">

                    <Button Margin="5">Do Something</Button>

                </Border>

            </ControlTemplate>

        </ContextMenu.Template>

    </ContextMenu>

</TextBlock.ContextMenu>

Now, when I right-click my record, a context menu (that doesn’t look like your traditional context menu) displays. I can fully interact with any controls in my ControlTemplate. When a button (with an event handler) is clicked or when I click outside of the ContextMenu, the menu hides itself. Exactly what I wanted.

I hope that this saves someone some time!

Tags: , ,

WPF

Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen

About the author

Chad

Meeeee!!!

Hi, my name is Chad Boschert and I'm a software developer in Springfield, Missouri. I've been developing .NET applications in C# since 2002.

Recent Comments

Comment RSS

Calendar

<<  June 2013  >>
MoTuWeThFrSaSu
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

View posts in large calendar