Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

15
Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler www.red-gate.com 1 Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler This walkthrough illustrates how to locate a memory leak using a sample application called QueryBee. QueryBee is a simple WinForms application for running queries against SQL Server databases. It is made up of a database connection dialog and a query window to query the database. We know our application is leaking memory, because every time we open a query window and close it again, our memory usage increases. On opening up ANTS Memory Profiler , we are presented with a setup dialog. Figure 1. The ANTS Memory Profiler setup dialog.

Transcript of Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

Page 1: Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler

www.red-gate.com 1

Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler

This walkthrough illustrates how to locate a memory leak using a sample application called QueryBee. QueryBee is a simple WinForms application for running queries against SQL Server databases. It is made up of a database connection dialog and a query window to query the database. We know our application is leaking memory, because every time we open a query window and close it again, our memory usage increases.

On opening up ANTS Memory Profiler, we are presented with a setup dialog.

Figure 1. The ANTS Memory Profiler setup dialog.

Page 2: Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler

www.red-gate.com 2

All we need to do is point it at QueryBee and click Start Profiling. The profiler

starts up QueryBee and begins collecting performance counter data.

Figure 2. Whilst profiling, ANTS Memory Profiler collects performance counter data. The pro-filer is telling us that it’s profiling our application; there are also some useful instructions on this screen telling us to take and compare snapshots.

Taking and comparing memory snapshots is a key activity when looking for memory leaks, so our approach will be as follows:

1. Wait for QueryBee to open.2. Take a first snapshot without using the application; this first snapshot will be

used as a baseline.3. Within QueryBee, perform the actions that we think cause the memory leak.4. Take a second snapshot.5. Examine the comparison that the profiler shows us after it has finished

taking and analyzing the second snapshot.

So, QueryBee is open, sitting in our system tray.

Page 3: Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler

www.red-gate.com 3

At this point, we take a first snapshot, which we will use as a baseline for comparison with later snapshots. When we click the Take Memory Snapshot button, the memory profiler forces a full garbage collection and takes a snapshot of the heap memory it is using.

Figure 3. Results from our first snapshot – Summary screen.

Now, we go back to QueryBee and perform the tasks which we think cause the memory leak.

We open up QueryBee and connect to a database.

Page 4: Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler

www.red-gate.com 4

Figure 4. QueryBee – Database connection dialog.

Figure 5. QueryBee – The query window.

The query window opens up and we enter and execute a SQL query.

We obtain some results and close the query window.

Page 5: Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler

www.red-gate.com 5

Figure 6. QueryBee – The results are displayed in a grid.

We close the query form.

At this point, the window is gone. We expect the memory usage to fall back to where it was in the first snapshot, but that is not the case.

Figure 7. Despite closing our query window, the memory usage has not fallen.

Page 6: Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler

www.red-gate.com 6

So what’s happening here? We take a second snapshot and get the results.

Figure 8. The summary pane compares the results of the two snapshots.

A number of problems are highlighted by the summary screen.

• We can see a large memory increase between snapshots, which we noticed on the timeline (top left).

• The Large Object Heap appears to be fragmented, which could cause problems (top right).

• The Generation 2 heap accounts for a large proportion of memory usage - often indicating objects are being held onto for longer than necessary (bottom left).

We can choose to select one of the largest classes which are shown to us in the bottom right of the screen, but instead we switch to the class list to find out more. The class list gives us a fuller picture of what’s in the snapshot.

Page 7: Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler

www.red-gate.com 7

We are interested in objects which have been created since the baseline snapshot, so we need to look at types which have more instances in the second snapshot. We therefore sort by Instance Diff in decreasing order.

Figure 9. The class list allows you to compare memory usage in both snapshots in more detail.

The String class has been placed at the top of the list, with over 540,000 new instances. We want to understand why there is such a large increase so load the Instance Categorizer for the String class by clicking the icon.

Figure 10. The Instance Categorizer shows chains of instances sorted by their shortest path to GC Root.

Click on image for larger view

Page 8: Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler

www.red-gate.com 8

We see that over 21MB of the String class are held in memory by the same shortest path back to GC Root, via our QueryForm and ConnectForm. We select Show the Instances on this Path to view a list of every instance in the previous category.

Figure 11. The instance list view shows us a set of strings which we recognize as coming from our SQL Database.

The Instance List is showing us data which QueryBee had retrieved from the SQL Database, but that data should have been destroyed when QueryForm was closed. We select one of the instances and click the icon to generate an Instance Retention Graph.

Page 9: Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler

www.red-gate.com 9

Figure 12. This instance retention graph.

Using the instance retention graph, we should be able to find out what is still referencing our String instances. Then, we’ll be able to go back into our code to break the chain of references that is keeping them in memory.

Page 10: Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler

www.red-gate.com 10

We start at the bottom and work our way up the graph until we find a reference that needs to be broken. We’ll just need to break the chain at one point to allow the garbage collector to clean up everything below that.

By navigating up, we can see the string is being held onto by QueryForm, even though that should have been released from memory. Looking a little further up, the graph is telling us that a System.EventHandler is referencing QueryForm and, if we step up one more level, it’s telling us that the event handler is referenced by our ConnectForm instance – this is the form that asked us for the database connection details. In other words, the ConnectForm is holding onto the QueryForm via an Event Handler.

If we look at this node more closely, we see that it’s actually being referenced by the ConnectForm’s Foregrounded field.

Let’s find this Foregrounded event in our code. We right-click on the QueryBee.ConnectForm node and open the ConnectForm source code in Visual Studio™.

Figure 13. Foregrounded event in the ConnectForm source code.

Page 11: Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler

www.red-gate.com 11

The profiler automatically jumps to the Foregrounded event. We check where it is being used by right-clicking on Find All References.

Figure 14. The Foregrounded event is used in three places.

We’ve got three usages and we find that the last usage is where QueryForm registers for the Foregrounded event, but it doesn’t look like it unregisters. If we fix that, then the memory leak should go away.

Once we’re done, we need to rebuild, but first we need to stop profiling QueryBee so that the executable isn’t locked. We go back to Profiler and click on the Stop Profiling button.

Then, we rebuild.

Figure 15. We rebuild our QueryBee application.

Page 12: Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler

www.red-gate.com 12

Figure 16. The settings dialog remembers settings from last time.

We take a first snapshot to use as a baseline.

Back in the profiler, we start up a new profiling session. We want to find out whether the reference to the QueryForm has disappeared.

Note that it remembered our settings from last time, so all we need to do is click Start Profiling.

Page 13: Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler

www.red-gate.com 13

Figure 17. Results from first snapshot.

We connect to a database and execute a SQL query.

Now, we’ll take an extra snapshot, because we want to be able to verify that the QueryForm has disappeared.

Finally, we close the query window with the results grid and we take a third snapshot.

We switch to a comparison between snapshots 1 and 3, using the snapshot selection field just under the timeline.

Page 14: Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler

www.red-gate.com 14

Figure 18. Summary screen comparing snapshots 1 and 3.

We can see there is now only a small memory increase between the snapshots, which is promising. Let’s see if there’s a QueryForm still in the class list.

We switch to the class list view and search only for classes in the QueryBee namespace.

Page 15: Profiling the Memory Usage of a .NET Application With ANTS Memory Profiler

Profiling the Memory Usage of a .NET Application with ANTS Memory Profiler

www.red-gate.com 15

Figure 19. Class list for the QueryBee namespace.

No, it’s gone. We’re no longer leaking the form.

As you saw, it was fairly easy to track down a form which was being leaked.

Why not download ANTS Memory Profiler, give it a try on your application, and see for yourself how it can help you locate memory leaks?

Download a free trail:www.red-gate.com/products/dotnet-development/ants-memory-profiler/download