Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια

C# and .NET Tips and Tricks

Quests in programming in .NET
A simple way to detect memory leaks in C# and how to create one with events :)

In this post we will see a simple code fragment that can be used to detect memory leaks (more specific objects that are not cleaned by the garbage collector) and we will do it in the context of an interesting memory leak that can be created when using event delegates.

The memory leak with event delegates

Suppose you have an application in WPF with a single window that presents some money values in a specific currency (say EURO). At a specific instance you may have more than one such windows open.

Now a requirement comes that defines that you need to be able to change the currency (say from euro to dollar) and have this change be reflected immediately to any currently open window displaying the money value. One easy way to tackle this is shown in the following figure:

The "settings" object is static with a static property "Currency" with the current currency and an event called "OnCurrencyChanged" that is fired when the currency is changed. The "Window" class ("window1" nad "window2" objects) defines a method "currencyChanged". When a window is opened it attaches the "currencyChanged" method to the "OnCurrencyChanged" event. This method will be called whenever the event is fired and will be responsible for converting the money values in the windows. Let's see some code for that. First the "settings" class:

public static class settings
{
    public static event Action OnCurrencyChanged;

    public static void ChangeCurrency(string newCurrency)
    {
        //...
        if (OnCurrencyChanged != null)
            OnCurrencyChanged(newCurrency);
    }

}				

The code for the window with the money values has the "currencyChanged" method:

public partial class MoneyWindow : Window
{
    public MoneyWindow()
    {
        InitializeComponent();
    }

    public void currencyChanged(string newCurrency)
    {
        // Change the view to reflect the change here
    }
}				

The initializer of the window with the money values will be as follows:

MoneyWindow dlg = new MoneyWindow();
dlg.Show();
settings.OnCurrencyChanged += dlg.currencyChanged;	

Which in other words defines that when the window is created it will be listening to the "OnCurrencyChanged" event.

And you have your memory leak right there! Even if you close the window in some time, the event you have attached still keeps it "connected" to your application and therefore it will never be garbage collected. Just for a reminder, the objects are destroyed by the garbage collector when there are no other objects pointing to them. But in this case you have an "implicit" connection with the event. If you execute the demo application (here) you will see that opening and closing the window keeps consuming more and more memory which never gets freed (it helps to have the "Task Manager" open to test that). The solution is simple and it just requires you to unsubscribe from the event with "-=" when the window is closed. But say you are in a large application you are not sure whether an object gets garbage collected or not and wanna check that then what can you do?.

Detecting memory leaks

Or better checking whether an object will get garbage collected. Implement in your project a class like the following:

public static class MemoryLeak
{
    public static WeakReference Reference { get; private set; }

    public static void CheckObject(object ObjToCheck)
    {
        MemoryLeak.Reference = new WeakReference(ObjToCheck);
    }

    public static void IsItDead()
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();
        if (MemoryLeak.Reference.IsAlive)
            Debug.WriteLine("Still here");
        else
            Debug.WriteLine("I 'm dead");
    }
}				

The code creates a weak reference to an object. The "weak reference" means that while it keeps a reference to the object this does not prevent the garbage collector from cleaning it (in other words this reference does not count in terms of collecting the object when not referenced). So we create the reference and then by calling "IsItDead" we just force the GC to collect any unneeded objects. If the object in question still persists then we have a memory leak.

For our example above, when we create the window we create a weak reference to the window object. Then we create a button that calls the "IsItDead" method. If we do not have a memory leak then the method should return "Still here" while the window is open and "I 'm dead" a while after the window is closed.

You can download the demo project here

Share
Posted: Κυριακή, 26 Μαΐου 2013 5:31 μμ από το μέλος iwannis
Δημοσίευση στην κατηγορία: ,

Σχόλια:

Χωρίς Σχόλια

Ποιά είναι η άποψή σας για την παραπάνω δημοσίευση;

(απαιτούμενο)

(απαιτούμενο)

(προαιρετικό)

(απαιτούμενο)
ÅéóÜãåôå ôïí êùäéêü:
CAPTCHA Image

Ενημέρωση για Σχόλια

Αν θα θέλατε να λαμβάνετε ένα e-mail όταν γίνονται ανανεώσεις στο περιεχόμενο αυτής της δημοσίευσης, παρακαλούμε γίνετε συνδρομητής εδώ

Παραμείνετε ενήμεροι στα τελευταία σχόλια με την χρήση του αγαπημένου σας RSS Aggregator και συνδρομή στη Τροφοδοσία RSS με σχόλια