Telerik JustTrace is a new performance and memory profiling utility, and the beta was released last week. Like many people, I’ve built projects with a focus on ensuring the functionality works, but it is vital that your application performs well without consuming unnecessary resources when it is finally delivered. To determine if there are issues I should be addressing, I downloaded the JustTrace beta and put my Win7 multitouch demo application, TouchCafe, to the the test.
A quick note if you have trouble installing the beta due to privileges: run a command-line as administrator then run the installer. According to the forums, this installer issue is fixed in the current internal build and the next release will address this issue as well.
JustTrace integrates with Visual Studio, but you can also run the standalone profiler to have access to more options. I opted to run the standalone version. After loading it up, I had the option to profile an application.

This brought me to a screen where I can enter the requisite options for profiling the application. In this situation, I wanted to run a local application with a memory profiler. There are other options for running, Silverlight, and IIS applications. There are also two other profiler types: sampling and tracing. I won’t be using these for this article, but if you have an open source project you would like me to help out with, and you don’t mind having an article written on the experience, send me a message through the contact form.

Clicking Run started up the application.

It is important that I list out my expectations so we know what to look for. Touch Café is a multitouch-enabled WPF application using a custom MVVM framework. It isn’t very complicated, and as such I do not expect it to have memory leaks. If it did have memory leaks, they would unlikely be detected by resource consumption due to the small-size of the application, but of course if the prototype was turned into a production application, the leaks would eventually become noticeable.
I expect the .NET framework to hold on to specific references for performance reasons. However, the memory size should not grow after one pass through the system. Also, no references of my application classes should exist between passes. I expect each ViewModel and Model to be collected when they are no longer required. Let’s see what happens.
I first collect a snapshot of my app at startup. This is my baseline.

I then go through every screen in this program. Since it’s a wizard-style ordering system, it will return to the main screen. At this point, application class instances should be identical to the baseline. Note that in a larger application, I would target areas suspected of having issues. I select the Terminate and Save Snapshot button after I return the main screen.

With the two snapshots available, I compared the completed snapshot to the baseline. I found that the application is holding on to instances!
The baseline contains the following:
1 TouchCafe.Views.StartView
1 TouchVafe.ViewModels.StartViewModel
1 TouchCafe.Service.PointOfSaleService
4 TouchCafe.Rule<TouchCafe.Models.OrderModel>
1 TouchCafe.OrderRouter
1 TouchCafe.Models.OrderModel
1 TouchCafe.Models.ItemModel[]
1 TouchCafe.Models.MainWindow
1 TouchCafe.DelegateCommand
1 TouchCafe.App
Our comparison snapshot contains:
1 TouchCafe.Views.StartView
1 TouchCafe.Views.CompleteView
1 TouchCafe.Views.CheckoutView
1 TouchVafe.ViewModels.StartViewModel
1 TouchCafe.ViewModels.CompleteViewModel
1 TouchCafe.ViewModels.CheckoutViewModel
2 TouchCafe.Service.PointOfSaleService
1 TouchCafe.Selectable<TouchCafe.Models.ItemModel>[]
4 TouchCafe.Rule<TouchCafe.Models.OrderModel>
1 TouchCafe.OrderRouter
1 TouchCafe.Models.OrderModel
1 TouchCafe.Models.ItemModel[]
1 TouchCafe.Models.MainWindow
3 TouchCafe.DelegateCommand
1 TouchCafe.App
So basically we’ve ended up with following extra items:
1 CompleteView & CompleteViewModel
1 CheckoutView & CheckoutViewModel
1 PointOfSaleService
1 Selectable<ItemModel>[]
The fact that it’s creating a PointOfSaleService through each pass is an issue that needs to be addressed. However, the fact that the views exist may not be so bad as long as it doesn’t hold onto new instances through each pass. In the real world, I would need to prioritize my time, and I may only need to address this if new instances are created without being freed through each pass. I profile again and add an extra pass.
The next pass revealed something interesting. There are no actual leaks in the application classes, although it’s not managing the instances as expected. Also, it’s always holding on to two PointOfSaleService instances. At this point, I wouldn’t consider this exercise critical, and other issues would normally take priority. But, I don’t like unresolved mysteries in blog posts. Let’s dig into the code and figure out what’s going on.
The PointOfSaleService is a stub class for calling the server in the restaurant. It would do things like send orders to the kitchen and such. I open up the file and use JustCode to find usages.

Mystery solved. An instance of CheckoutViewModel is available, and it has an instance of PointOfSaleService.
What about the views?
Each view is a user control. Determining which view is on the screen is the responsibility of the OrderRouter class. The OrderRouter class needs a container in which to display the views, and it depends on rules to determine which view to go to next. I never had a session to determine if this was the best approach, or if the class is of the best design. Certainly, there are a few names that should be changed. However, I will present them to you now as we determine why references are being maintained.
First, the rule class:
public class Rule<T>
{
private Func<T, bool> predicate;
private Action<T> action;
private bool terminateOnSuccess;
public Rule(Func<T, bool> predicate, Action<T> action) : this(predicate, action, true) { }
public Rule(Func<T, bool> predicate, Action<T> action, bool terminateOnSuccess)
{
this.predicate = predicate;
this.action = action;
this.terminateOnSuccess = terminateOnSuccess;
}
public Rule<T> Next { get; private set; }
public Rule<T> Add(Func<T, bool> predicate, Action<T> action)
{
return Add(predicate, action, true);
}
public Rule<T> Add(Func<T, bool> predicate, Action<T> action, bool terminateOnSuccess)
{
if (Next != null)
{
Next.Add(predicate, action, terminateOnSuccess);
return this;
}
Next = new Rule<T>(predicate, action, terminateOnSuccess);
return this;
}
public void Execute(T item)
{
if (predicate(item))
{
action(item);
if (terminateOnSuccess)
{
return;
}
}
if (Next != null)
{
Next.Execute(item);
}
}
}
public static class Rule
{
public static Rule<T> Create<T>(Func<T, bool> predicate, Action<T> action)
{
return new Rule<T>(predicate, action);
}
public static Rule<T> Create<T>(Func<T, bool> predicate, Action<T> action,
bool terminateOnSuccess)
{
return new Rule<T>(predicate, action, terminateOnSuccess);
}
}
And now the OrderRouter class:
public class OrderRouter
{
private UIElementCollection container;
private Rule<OrderModel> routeRules;
private static OrderRouter instance;
public static OrderRouter Instance
{
get
{
if (instance == null)
{
instance = new OrderRouter();
}
return instance;
}
}
private OrderRouter()
{
routeRules = Rule.Create<OrderModel>(o => o.Status == OrderStatus.New, o => Route())
.Add(o => o.Status == OrderStatus.NameChosen,
o => container.Add(new OrderView(new OrderViewModel(o))))
.Add(o => o.Status == OrderStatus.ItemsSelected,
o => container.Add(new CheckoutView(new CheckoutViewModel(o))))
.Add(o => o.Status == OrderStatus.Submitted,
o => container.Add(new CompleteView(new CompleteViewModel(o))));
}
public OrderRouter RegisterContainer(UIElementCollection container)
{
this.container = container;
return this;
}
public void Route()
{
container.Clear();
container.Add(new StartView(new StartViewModel(new OrderModel())));
}
public void Route(OrderModel order)
{
container.Clear();
routeRules.Execute(order);
}
public void Route(ItemModel item)
{
container.Add(new ItemView(new ItemViewModel(item)));
}
public void Main()
{
while (container.Count > 1)
{
container.RemoveAt(1);
}
}
}
After each navigation, the container is cleared, with the exception of routing to a specific ItemModel. It’s an exception to the normal flow.
The rules create new instances each time. However, additional passes through the system do not cause additional instances beyond the first one. There’s also the curious case that neither ItemView nor OrderView have this issue. I suspect the items aren’t being collected on the first pass through the garbage collector due to the fact that the first two views I navigate to after the start screen aren’t showing in my list, and the instances aren’t accumulating.
It is best to let the garbage collector do as it pleases. It is optimized for the best performance for most situations, and you only need to change things on it in extreme circumstances. I’m going to call GC.Collect() in the Route() method to satisfy my curiosity, but I will remove it afterwards as the extra instances are not causing issues with the application.
public void Route()
{
container.Clear();
container.Add(new StartView(new StartViewModel(new OrderModel())));
GC.Collect();
}
The timing must be off as the CompleteView is still hanging around. However, CheckoutView is now collected after a pass through the system. Again, I forced a collection here to satisfy my curiosity… I am not leaving it in and in most cases you shouldn’t either.
Download Telerik JustTrace beta to profile your own applications! If you’re interested in the JustCode feature I used, download the trial then check out these 10 videos to make Visual Studio better with JustCode!