Learn to use Visual Studio, Visual Studio Online, Application Insights and Team Foundation Server to decrease rework, increase transparency into your application and increase the rate at which you can ship high quality software throughout the application lifecycle
This blog post is part of a series on breakpoints in the Visual Studio debugger.
In earlier posts, we shown hit count breakpoints and filter breakpoints , which both help a developer narrow down the scenarios in which a breakpoint it hit. A conditional breakpoint does the same, but it offers more flexibility by allowing the developer to customize the condition with any valid expression.
We will illustrate one way conditional breakpoints can be used, we will use our C++ example. We’ve noticed that we have a memory leak in this application, and we will use conditional breakpoints to help track it down.
Our application uses AddRef and Release and so an object is leaked when the program calls AddRef on an object more times than it calls Release. We will track this down by tracing the AddRef and Release functions with tracepoints.
At each of these tracepoints, we will print out the value of ulcRef as well as the current call stack.
Now when we run the application we get the following output.
Without even getting past the second tracepoint output, we can see that we have too much information here. We see two calls to AddRef that both have a refcount of 1. This is because we are seeing output for all objects being AddRef’d.
To narrow this down, we will set a condition on this tracepoint so that we only see this output for the object being leaked. To get started, first we need to get the address of the object being leaked. We do this by setting a breakpoint on the constructor. In this case, we will set a hit count breakpoint because we only want to hit this exactly once.
Now that we have the address of the leaked object, we can go back to our tracepoints and add a condition. To do this we right-click on the tracepoint and click Condition…
Then set the condition to match the value of “this” that you inspected at the constructor.
Create the same condition for both tracepoints. Now when you continue the execution, you can see the output just for that object in the Output window.
It is now easy to see that the object has 2 AddRef and only 1 release. Based on the call stack, the release is coming from the destructor, which matches the first AddRef called by the constructor. This leaves the AddRef of the CleanUp function as the extra one that needs to be removed (or paired up with some Release call) to fix the leak.