Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preventing Memory Leaks with Attached Behaviours

Tags:

.net

memory

wpf

I've created an "attached behaviour" in my WPF application which lets me handle the Enter keypress and move to the next control. I call it EnterKeyTraversal.IsEnabled, and you can see the code on my blog here.

My main concern now is that I may have a memory leak, since I'm handling the PreviewKeyDown event on UIElements and never explicitly "unhook" the event.

What's the best approach to prevent this leak (if indeed there is one)? Should I keep a list of the elements I'm managing, and unhook the PreviewKeyDown event in the Application.Exit event? Has anyone had success with attached behaviours in their own WPF applications and come up with an elegant memory-management solution?

like image 832
Matt Hamilton Avatar asked Aug 18 '08 00:08

Matt Hamilton


People also ask

Which of the following actions can cause memory leak?

Common causes for these memory leaks are: Excessive session objects. Insertion without deletion into Collection objects. Unbounded caches.

What is a memory leak and how would you handle it?

Description. Memory leaks are a class of bugs where the application fails to release memory when no longer needed. Over time, memory leaks affect the performance of both the particular application as well as the operating system. A large leak might result in unacceptable response times due to excessive paging.


3 Answers

@Nick Yeah, the thing with attached behaviours is that by definition they're not in the same object as the elements whose events you're handling.

I think the answer lies within using WeakReference somehow, but I've not seen any simple code samples to explain it to me. :)

like image 159
Matt Hamilton Avatar answered Sep 20 '22 12:09

Matt Hamilton


Philosophical debate aside, in looking at the OP's blog post, I don't see any leak here:

ue.PreviewKeyDown += ue_PreviewKeyDown;

A hard reference to ue_PreviewKeyDown is stored in ue.PreviewKeyDown.

ue_PreviewKeyDown is a STATIC method and can't be GCed.

No hard reference to ue is being stored, so nothing is preventing it from being GCed.

So... Where is the leak?

like image 27
John Fenton Avatar answered Sep 16 '22 12:09

John Fenton


To explain my comment on John Fenton post here is my answer. Lets see the following example:

class Program
{
    static void Main(string[] args)
    {
        var a = new A();
        var b = new B();

        a.Clicked += b.HandleClicked;
        //a.Clicked += B.StaticHandleClicked;
        //A.StaticClicked += b.HandleClicked;

        var weakA = new WeakReference(a);
        var weakB = new WeakReference(b);

        a = null;
        //b = null;

        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();

        Console.WriteLine("a is alive: " + weakA.IsAlive);
        Console.WriteLine("b is alive: " + weakB.IsAlive);
        Console.ReadKey();
    }


}

class A
{
    public event EventHandler Clicked;
    public static event EventHandler StaticClicked;
}

class B
{
    public void HandleClicked(object sender, EventArgs e)
    {
    }

    public static void StaticHandleClicked(object sender, EventArgs e)
    {
    }
}

If you have

a.Clicked += b.HandleClicked;

and set only b to null both references weakA and weakB stay alive! If you set only a to null b stays alive but not a (which proves that John Fenton is wrong stating that a hard reference is stored in the event provider - in this case a).

This lead me to the WRONG conclusion that

a.Clicked += B.StaticHandleClicked;

would lead to a leak because i though the instance of a would be kept by the static handler. This is not the case (test my program). In the case of static event handler or events it is the other way around. If you write

A.StaticClicked += b.HandleClicked;

a reference will be kept to b.

like image 38
Daniel Bişar Avatar answered Sep 20 '22 12:09

Daniel Bişar