New memory profiler in Visual Studio 2015
- Tutorial
For many years, C ++ programmers writing under Linux viciously blamed the developers on C ++ under Windows for the lack of a normal memory profiler in Visual Studio. Here, in Linux, they say, there is Valgrind, which solves all problems, but in the studio that: arrange some macros, analyze some logs - darkness. Slander! Although true. Rather, this was true before the release of Visual Studio 2015, in which at last (hurray 3 times!) There is a normal memory profiler that allows you to catch memory leaks with your eyes closed, one left and not even waking up!
In this article we will see what he knows and how to use it.
We start Visual Studio 2015, create a new console project in C ++ and write the following code into it:
Now run the application under the debugger (F5) and see the Diagnostic Tool panel that appears in Visual Studio (see the screenshot above).
It shows CPU and memory utilization, but we are not interested in this. The most valuable thing in this panel is the lower part, which allows us to take snapshots of the application’s memory at any given time. By default, this feature is disabled (because it slows down the application), to enable it, click the "Enable snapshots" button and restart the application under the debugger.
Now the “Take Snapshot” button becomes available to us, let's click it.
And we got the first shot of memory! We can click on it twice and see what's inside:
We see a list of all the memory allocations that occurred in our process, the types of variables created, their number and size in bytes. Our application is as simple as doors, but still ... What is this char [] array of 100 bytes in size? How to find out where it is created? Just click on it twice - we get into the list of instances of objects of this type. We have only one. At the bottom of the window we see a call stack, in the course of which this memory block was allocated. We look who is at the top of this stack:
So, this is the main () function, line number 9. Double-click will take us directly to the code.
Oh my god, how so! It turns out that I was just going to write the simple code that I quoted above, and along the way I created a 100-byte array in a loop that is not deleted anywhere and leads to a memory leak. I don’t even know how I would have found it, if not for the new Visual Studio profiler!
“Okay, enough to be kidding,” the practically-minded reader will say, “he found the allocation of one array in a program of 7 lines, where no other memory is allocated. I have 150 thousand classes and code as text in the “War and Peace” project, you’ll try to find where it’s leaking out there! ”
And let's try. For realism, we will create a new MFC project that pulls (surprise!) - MFC. We create the project with a standard wizard, without changing anything. And here we have an empty project of 55 files - long live the “minimalism” of MFC. Well at least builds.
We find the CMFCApplication1App :: OnAppAbout () method and add the memory leak we are already familiar with:
Now run this application under the memory profiler. As you might imagine, already during the launch of the MFC takes over memory. Immediately after starting, we will create the first snapshot of the memory, and then press the “About” button 10 times. Each time a modal dialog will be shown (which will lead to a number of memory allocation and deallocation operations) and, as you might guess, 100 bytes of memory will leak every time. In the end, create another snapshot of the memory - now we have two of them.
The first thing we see is the difference in the amount of allocated memory - in the second picture there are 58 more allocations, which in total is 15.71 KB. Basically, this is the memory allocated by MFC for its internal needs (just like in your project with 150 thousand classes, right?), Which then, probably, will be released by MFC. But we are not interested in it, but in memory leaks in our code. Let's open the second snapshot:
In principle, some conclusions can already be drawn from here: we have 10 pointers to char, 100 bytes each - it is likely that 10 memory allocations are associated with 10 clicks on the button, which means you can look for the number “100” in the code well, or go along the call stack to the memory allocation location for this array. But okay, let's complicate our task - let's imagine that we have here not 7 lines with pointers to the allocated memory, but 700 or 7000. Among them there may be larger blocks and other blocks that exist in the amount of 10 copies. How can we track only what was created between two snapshots of memory? Elementary - for this there is a combo “Compare to” at the top of the window. Just select picture No. 1 there and see only the difference between the moment before the first click on the button and the moment after the 10th click. Now the plate looks much cleaner
Plus we have sorting by columns and searching by data types.
In general, the tool from Microsoft turned out to be a very good, just rare case, when everything you need is in place and there is nothing superfluous.
In this article we will see what he knows and how to use it.
We start Visual Studio 2015, create a new console project in C ++ and write the following code into it:
#include<iostream>intmain(){
for (;;)
{
std::cout << "Hello, Habr!";
getchar();
}
return0;
}
Now run the application under the debugger (F5) and see the Diagnostic Tool panel that appears in Visual Studio (see the screenshot above).
It shows CPU and memory utilization, but we are not interested in this. The most valuable thing in this panel is the lower part, which allows us to take snapshots of the application’s memory at any given time. By default, this feature is disabled (because it slows down the application), to enable it, click the "Enable snapshots" button and restart the application under the debugger.
Now the “Take Snapshot” button becomes available to us, let's click it.
And we got the first shot of memory! We can click on it twice and see what's inside:
We see a list of all the memory allocations that occurred in our process, the types of variables created, their number and size in bytes. Our application is as simple as doors, but still ... What is this char [] array of 100 bytes in size? How to find out where it is created? Just click on it twice - we get into the list of instances of objects of this type. We have only one. At the bottom of the window we see a call stack, in the course of which this memory block was allocated. We look who is at the top of this stack:
So, this is the main () function, line number 9. Double-click will take us directly to the code.
Oh my god, how so! It turns out that I was just going to write the simple code that I quoted above, and along the way I created a 100-byte array in a loop that is not deleted anywhere and leads to a memory leak. I don’t even know how I would have found it, if not for the new Visual Studio profiler!
“Okay, enough to be kidding,” the practically-minded reader will say, “he found the allocation of one array in a program of 7 lines, where no other memory is allocated. I have 150 thousand classes and code as text in the “War and Peace” project, you’ll try to find where it’s leaking out there! ”
And let's try. For realism, we will create a new MFC project that pulls (surprise!) - MFC. We create the project with a standard wizard, without changing anything. And here we have an empty project of 55 files - long live the “minimalism” of MFC. Well at least builds.
We find the CMFCApplication1App :: OnAppAbout () method and add the memory leak we are already familiar with:
CMFCApplication1App::OnAppAbout()
{
CAboutDlg aboutDlg;
aboutDlg.DoModal();
char* l = new char[100];
}
Now run this application under the memory profiler. As you might imagine, already during the launch of the MFC takes over memory. Immediately after starting, we will create the first snapshot of the memory, and then press the “About” button 10 times. Each time a modal dialog will be shown (which will lead to a number of memory allocation and deallocation operations) and, as you might guess, 100 bytes of memory will leak every time. In the end, create another snapshot of the memory - now we have two of them.
The first thing we see is the difference in the amount of allocated memory - in the second picture there are 58 more allocations, which in total is 15.71 KB. Basically, this is the memory allocated by MFC for its internal needs (just like in your project with 150 thousand classes, right?), Which then, probably, will be released by MFC. But we are not interested in it, but in memory leaks in our code. Let's open the second snapshot:
In principle, some conclusions can already be drawn from here: we have 10 pointers to char, 100 bytes each - it is likely that 10 memory allocations are associated with 10 clicks on the button, which means you can look for the number “100” in the code well, or go along the call stack to the memory allocation location for this array. But okay, let's complicate our task - let's imagine that we have here not 7 lines with pointers to the allocated memory, but 700 or 7000. Among them there may be larger blocks and other blocks that exist in the amount of 10 copies. How can we track only what was created between two snapshots of memory? Elementary - for this there is a combo “Compare to” at the top of the window. Just select picture No. 1 there and see only the difference between the moment before the first click on the button and the moment after the 10th click. Now the plate looks much cleaner
Plus we have sorting by columns and searching by data types.
In general, the tool from Microsoft turned out to be a very good, just rare case, when everything you need is in place and there is nothing superfluous.