Memory Management

Silverlight Getting Worse When It Comes To Memory Leaks

15 commentsWritten on August 19th, 2010 by
Categories: Memory Management, Silverlight

A coworker of mine spent some hours yesterday hunting down memory leaks in an app that he'd already gotten 'leak-free' back when it was in Silverlight 3. Turns out that the leaks are caused by changes in Silverlight 4 and not in our code. As you surely know, Microsoft releases major Silverlight versions pretty frequently (there's at least one major new version each year). That's great and all when it comes to introducing new features and capabilities, but it truly sucks if you keep introducing new problems as well. The total amount of time (and thus, money) that we've lost hunting down leaks that are located in either the core Silverlight code or the Control Toolkit (also Microsoft code) is just starting to become embarrassingly high.

To give you an idea of what kind of leaks that keep popping up, be sure to check out these links: http://forums.silverlight.net/forums/t/179177.aspx http://forums.silverlight.net/forums/t/179358.aspx http://forums.silverlight.net/forums/t/180702.aspx http://forums.silverlight.net/forums/t/181257.aspx http://forums.silverlight.net/forums/t/171739.aspx

If anyone from Microsoft reads this: please, pretty please, pretty please with sugar on top: can we get a little bit more QA from you guys? If you can put out products like WebMatrix and LightSwitch, than surely you must have enough resources available to make sure that your real development platforms do not become a cost-sink for your customers due to your own lack of quality control, no?

Update: it's also quite telling that the search phrase "silverlight memory leak" is the number one search phrase through which people get to this site. #justsaying

Avoiding Memory Leaks With NServiceBus And Your Own Castle Windsor Instance

15 commentsWritten on February 19th, 2010 by
Categories: Castle Windsor, Memory Management, nservicebus

If you’re using NServiceBus together with your own instance of Castle Windsor, there is one thing you really need to look out for.  NServiceBus was originally developed with Spring.NET as its IoC container, but it’s been changed to support multiple containers in a similar manner as Agatha does it.  Agatha however, was originally developed with Castle Windsor as its IoC container, and as such is well aware of Windsor’s need to explicitly release resolved components.   NServiceBus unfortunately was not aware of this need, and a workaround that they have introduced is to set Windsor’s ReleasePolicy to the NoTrackingReleasePolicy (which doesn’t hold any instances in memory, but doesn’t provide any cleanup either) if you configure NServiceBus to use its own instance of Castle Windsor.  However, if you’re integrating NServiceBus into a project that is already using Castle Windsor, then you probably want NServiceBus to use your instance of Castle Windsor.

And that is when problems might appear.  If you’re using Castle Windsor with the default ReleasePolicy (which is the LifecycledComponentsReleasePolicy) then each resolved transient instance will be stored in memory by that policy until the instance is explicitly released.  The benefit of this policy is that the container can automatically dispose any disposable transient dependency of a resolved component.  In my case, i’ve come to rely on that feature to achieve deterministic disposal behavior throughout my code base. 

Now, when you configure NServiceBus and pass it your instance of Castle Windsor, it obviously doesn’t change the ReleasePolicy like it does when it creates its own instance of Castle Windsor.   This is good because changing the policy of a passed in container would almost certainly have a huge behavioral implication for the application and such an action would be unacceptable when integrating a new framework into your project.   But since NServiceBus doesn’t have the notion of needing to release resolved components, every single transient instance it resolves through your container will be stored in memory until the application’s process is terminated.  Which means that you’ll leak instances of the following types for each message that your system needs to handle:

  • NServiceBus.Grid.MessageHandlers.GridInterceptingMessageHandler
  • NServiceBus.Sagas.Impl.SagaMessageHandler
  • Your own MessageHandlers (and their transient dependencies as well)

If your MessageHandlers don’t have dependencies (highly unlikely if you’re already using an IOC container) then you’d still have 3 leaking instances per incoming message.  Add the number of transient dependencies of any handler to that and the number of leaking instances can increase dramatically.

First of all, if you do not depend on Windsor’s default ReleasePolicy’s behavior, then the easiest way to avoid this problem is definitely to set the container’s ReleasePolicy to the NoTrackingReleasePolicy like NServiceBus does itself when it’s configuring itself with a new instance of the container.

If you do depend on it, and you don’t want leaking instances that hang around forever, then the approach listed below is one way to solve this problem.  There are probably other solutions available, and while the approach listed below can definitely be considered to be a HACK, i do think it’s the best solution to this particular problem.

Because we don’t want to change anything about the way that we’re already using the container, we just need to make sure that NServiceBus’ usage of the container doesn’t conflict with ours.  That basically means that we need to make sure that the components that it resolves should not be tracked by the container.   There are 2 kinds of components that NServiceBus will resolve during normal operation:

  1. Its own components that it needs to implement the features it offers you
  2. Your message handlers that you need to handle incoming messages

The first category is easy to exclude from Windsor’s tracking behavior.  We can simply create our own ReleasePolicy which extends the default ReleasePolicy, and make sure that any instances of an NServiceBus-type are no longer tracked by the container:

    public class MyReleasePolicy : Castle.MicroKernel.Releasers.LifecycledComponentsReleasePolicy

    {

        public override void Track(object instance, Castle.MicroKernel.Burden burden)

        {

            if (!instance.GetType().FullName.StartsWith("NServiceBus"))

            {

                base.Track(instance, burden);

            }

        }

    }

 

Then you need to set this release policy somewhere in your application’s startup routine:

            IoC.Container.Kernel.ReleasePolicy = new MyReleasePolicy();

 

(in this case, IoC.Container returns an IWindsorContainer instance)

This will make sure that no instances of NServiceBus-types will ever leak in the container.  But now we still have to deal with our message handlers.  The solution to making sure they are not disposed is not the cleanest out there but hey, it works.  I basically introduced a base class that all my message handlers will need to inherit from, with the following implementation in the Handle method:

    public abstract class MessageHandler<TMessage> : IMessageHandler<TMessage> where TMessage : IMessage

    {

        public void Handle(TMessage message)

        {

            try

            {

                Process(message);

            }

            finally

            {

                // ugly as hell, but we need this until NSB releases its resolved components

                IoC.Container.Release(this);

            }

        }

 

        protected abstract void Process(TMessage message);

    }

 

Uh oh… i just felt a great disturbance in the Force, as if tens of voices suddenly cried out in terror about my direct usage of the IoC container in a component!

Conceptually, this is wrong on many levels.  Then again, this makes sure that the message handlers (and their dependencies) that are resolved by NServiceBus will always be guaranteed to be released by the comtainer.  It might not be nice, but it avoids the memory leak and it doesn’t force me to change my other code.

And once NServiceBus is modified to release the components it resolves (if it’s ever modified that is…) i only need to get rid of my custom policy and the try/finally block.  Unfortunately, my existing message handlers will then all implement the Process method instead of the Handle method but that is quickly fixed with a simple rename-refactoring.

Even though this is a pretty big hack (IMHO), at least its impact on the code is minimal… it will be easy to get rid of once the real problem is solved in NSB, and there are no real downsides to this that i can think of at the moment.

Can You Come Up With A WHY Comment For This Code?

5 commentsWritten on February 18th, 2010 by
Categories: Memory Management

I just had to write the following code:

    public class MyReleasePolicy : Castle.MicroKernel.Releasers.LifecycledComponentsReleasePolicy

    {

        public override void Track(object instance, Castle.MicroKernel.Burden burden)

        {

            if (!instance.GetType().FullName.StartsWith("NServiceBus"))

            {

                base.Track(instance, burden);

            }

        }

    }

 

and then this:

            IoC.Container.Kernel.ReleasePolicy = new MyReleasePolicy();

 

to make a problem go away.

Can you come up with a WHY comment? (the category of this post is another hint)

Event Subscribtion And Memory Leaks (Yet Again)

31 commentsWritten on September 12th, 2009 by
Categories: Memory Management

Just read the following post by Fabrice Marguerie about forcing event unsubscription to avoid the typical memory leaks that occur frequently with event handlers. Unfortunately, the solution in his post will in most cases be useless.

First of all, consider the following 2 classes:

        public class Publisher
        {
            public event EventHandler<EventArgs> MyEvent = delegate { };
 
            public void RaiseEvent()
            {
                MyEvent(this, EventArgs.Empty);
            }
        }
 
        public class Subscriber
        {
            private static int counter;
 
            private int currentInstanceCount;
 
            public Subscriber(Publisher publisher)
            {
                currentInstanceCount = ++counter;
                publisher.MyEvent += producer_MyEvent;
            }
 
            void producer_MyEvent(object sender, EventArgs e)
            {
                Console.WriteLine(string.Format("Instance {0} is handling event...", currentInstanceCount));
            }
        }

Pretty simple... the Publisher publishes the MyEvent event, and the Subscriber subscribes to the event when an instance is created. As you should already know, whenever the publisher of an event has a longer lifecycle than its subscibers, subscribers must explicitly unsubscribe from the event to prevent instances of the subscribers to remain in memory instead of being garbage collected.

The following simple example illustrates the problem:

            var publisher = new Publisher();
 
            var subscriber1 = new Subscriber(publisher);
            var subscriber2 = new Subscriber(publisher);
 
            Console.WriteLine("triggering event for the first time... both subscribers should respond");
            publisher.RaiseEvent();
 
            subscriber1 = null;
            GC.Collect();
 
            Console.WriteLine("triggering event for the second time... hopefully, the first subscriber has been collected");
            publisher.RaiseEvent();
 
            subscriber2 = null;
            GC.Collect();
 
            Console.WriteLine("triggering event for the third time... hopefully, both subscribers have been collected");
            publisher.RaiseEvent();

This will produce the following console output:

triggering event for the first time... both subscribers should respond
Instance 1 is handling event...
Instance 2 is handling event...
triggering event for the second time... hopefully, the first subscriber has been collected
Instance 1 is handling event...
Instance 2 is handling event...
triggering event for the third time... hopefully, both subscribers have been collected
Instance 1 is handling event...
Instance 2 is handling event...

Obviously, both subscriber instances remained in memory even though we no longer had references to those instances and they should've been collected by the garbage collector. For those of you who don't know what's going on: an event handler will internally keep a list of references to all the objects that subscribed to the event. This means that it is only normal that the Publisher is actually keeping all of the Subscriber instances 'live' because it keeps references to it. That means that the garbage collector will never collect these instances until the Producer is eligible for garbage collection.

Now, Fabrice's proposed solution is to change the Producer to this:

        public class Publisher : IDisposable
        {
            public event EventHandler<EventArgs> MyEvent = delegate { };
 
            public void RaiseEvent()
            {
                MyEvent(this, EventArgs.Empty);
            }
 
            public void Dispose()
            {
                MyEvent = null;
            }
        }

Again, memory leaks through event subscription only occur when the publisher of an event lives longer than the subscribers of an event. Obviously, this solution will hardly help in the situation where the memory actually leaks, because the publisher will not be disposed of until it is no longer needed. Which means that the Producer will still keep all instances from no-longer-needed subscribers in memory.

The only way to avoid this problem is to explicitly unsubscribe each subscriber from the event. Which means that you should implement IDisposable on the Subscriber:

        public class Subscriber : IDisposable
        {
            private static int counter;
 
            private int currentInstanceCount;
            private Publisher publisher;
 
            public Subscriber(Publisher publisher)
            {
                currentInstanceCount = ++counter;
                this.publisher = publisher;
                publisher.MyEvent += producer_MyEvent;
            }
 
            void producer_MyEvent(object sender, EventArgs e)
            {
                Console.WriteLine(string.Format("Instance {0} is handling event...", currentInstanceCount));
            }
 
            public void Dispose()
            {
                publisher.MyEvent -= producer_MyEvent;
            }
        }

That's not enough though... you need to explicitly dispose these instances as well. So the example code now looks like this:

            var publisher = new Publisher();
 
            var subscriber1 = new Subscriber(publisher);
            var subscriber2 = new Subscriber(publisher);
 
            Console.WriteLine("triggering event for the first time... both subscribers should respond");
            publisher.RaiseEvent();
 
            subscriber1.Dispose();
            subscriber1 = null;
            GC.Collect();
 
            Console.WriteLine("triggering event for the second time... hopefully, the first subscriber has been collected");
            publisher.RaiseEvent();
 
            subscriber2.Dispose();
            subscriber2 = null;
            GC.Collect();
 
            Console.WriteLine("triggering event for the third time... hopefully, both subscribers have been collected");
            publisher.RaiseEvent();

And the output of this code is now correct:

triggering event for the first time... both subscribers should respond
Instance 1 is handling event...
Instance 2 is handling event...
triggering event for the second time... hopefully, the first subscriber has been collected
Instance 2 is handling event...
triggering event for the third time... hopefully, both subscribers have been collected

To summarize:

  • If a producer will stay alive longer than the subscriber, then it will keep the subscribers in memory until the publisher gets garbage collected

  • Your subscribers should explicitly unsubscribe from events from publishers, unless you know that the lifetime of both the subscriber or the publisher is either identical, or that the publisher has a shorter lifetime than the subscriber. You should preferably unsubscribe from these events in a Dispose method and your subscriber should implement IDisposable.

  • Always call the Dispose method on subscribers that implement IDisposable. Otherwise, you'll still leak instances of the subscribers.

Finding Memory Leaks In Silverlight With WinDbg

17 commentsWritten on August 8th, 2009 by
Categories: Memory Management, Silverlight

As i mentioned in a previous post, you can attach WinDbg to a browser to find memory leaks in your Silverlight applications. I figured it would be a good idea to write down how this process works, since i always end up having to look it up again whenever i need to do this.

I wrote a very simple Silverlight application which has a rather typical memory leak. Here's the actual code:

        public event EventHandler<MyEventArgs> MyEvent = delegate { };
 
        private void CreateNewViewButton_OnClick(object sender, RoutedEventArgs e)
        {
            ViewContainer.Children.Clear();
 
            var newView = new MyView();
            MyEvent += newView.EventHandler;
 
            ViewContainer.Children.Add(newView);
        }

For some of you, the memory leak is already very clear. Like i said, it's a very simple example ;)

Let's go through the process of finding and fixing the memory leak using WinDbg. First of all, download Debugging Tools For Windows (which contains the WinDbg executable) here and install it.

Then we start our application in Internet Explorer (for some reason i can't use WinDbg to inspect the managed memory heap with Firefox, so i just use Internet Explorer for this stuff) and use it. In the case of my example, that means clicking the button which creates a new view a couple of times.

Open WinDbg.exe and select the 'Attach to a Process' menu item in the 'File' menu and select the iexplore.exe process.

Then you need to load the correct version of sos.dll:

step1

After that we can see which types of our MySilverlightApplication namespace are present in the managed heap, including how many instances of them:

step2

As you can see, there are 13 instances of our MyView type present in the heap. Using the value in the MT column, we can drill down further:

step3

This shows the memory address of each instance of the MyView type in the heap. Now we can see if there are any live references to these instances:

step4

This is actually for the first address that was listed. As you can see, it is still a reachable reference, which means it will not be collected by the garbage collector. The chain of references clearly indicates that the instance is still referenced from our event in the MainPage instance. All of the previously listed instances show the same reference chain, so this is clearly a memory leak. Even though we should only have one active reference of MyView at any point in time of this application, the MyEvent event on MainPage clearly keeps each instance of MyView alive.

The correct way to fix this is to make sure that whenever we remove an instance of MyView, we need to unsubscribe it from the MainPage's MyEvent handler. Always remember this rule when it comes to dealing with events: if the publisher of the event has a longer lifetime than the subscriber of the event, then you absolutely have to unsubscribe each subscriber from the event or the publisher will keep references to each subscriber (preventing them from being garbage collected) for as long as the publisher is alive.

Here's the modified version of the above code which avoids the memory leak:

        public event EventHandler<MyEventArgs> MyEvent = delegate { };
 
        private void CreateNewViewButton_OnClick(object sender, RoutedEventArgs e)
        {
            CleanUpPreviousView();
 
            var newView = new MyView();
            MyEvent += newView.EventHandler;
 
            ViewContainer.Children.Add(newView);
        }
 
        private void CleanUpPreviousView()
        {
            if (ViewContainer.Children.Count > 0)
            {
                var myView = ViewContainer.Children[0] as MyView;
                if (myView != null) MyEvent -= myView.EventHandler;
                ViewContainer.Children.Clear();
            }
        }

Let's see if this really fixed the memory leak. If we fire up the application and press the button a couple of times, the application should normally only have one live reference of MyView in memory.

step5

I clicked the button 5 times, and the above output shows that there are 5 instances of MyView on the heap. So did we fix the leak or not? Check the output below:

step6

As you can see, only the last instance of MyView is actively referenced somewhere. That means that the first 4 instances are ready to be collected during the next garbage collection.

One thing i don't understand though, is that the reference chain of the last instance doesn't mention MainPage or the event handler anymore. But when i attached Visual Studio's debugger to the browser instance i could clearly see that the MyEvent of MainPage indeed contained an event handler that pointed to this MyView instance. I'm far from a WinDbg and SOS expert so i have no idea why the reference chain doesn't reflect this. Perhaps someone with more WinDbg and SOS knowledge can shed some light on this?

Either way, this approach is a pretty good way of finding memory leaks in your Silverlight code. In a real application it's obviously a bit more complicated to find the exact cause of a leak compared to this simple example, but it's still pretty doable. Just execute the !dumpheap -stat -type YourRootNameSpaceHere and look for unusually high numbers of instances of your types. Then you can start looking at each instance to figure out what's going on. And for a nice list of commands that you can execute in WinDbg with SOS, be sure to check this out.

Also, keep in mind that you can do this for every .NET process, and not just Silverlight. Though you would need to load the sos.dll file of your particular .NET version.