There are some features of Memory Validator that are useful to call directly from your program, including tracking of memory in custom heap managers.
Memory Validator has an API that makes this possible; just include svlMPAPI.c and svlMPAPI.h to your codebase. There is no library to link to, dlls to copy.
The source files can be found in the API directory in the Memory Validator install directory.
Just add these files to your project and build.
If you are using precompiled headers you will need to disable them for svlMVAPI.c.
If you are working with services you to attach Memory Validator to a service and to start Memory Validator, you should use the NT Service API, not the functions in this API.
All the other functions in this API can be used with applications and with services.
All the API functions are provided in Unicode and ANSI variants where strings are used. We've also provided a character width neutral #define in the same fashion that the Windows.h header files do.
For example the function for naming a heap is provided as mvSetHeapNameA(), mvSetHeapNameW() with the character width neutral mvSetHeapName() mapping to mvSetHeapNameW() for unicode and mvSetHeapNameA() for ANSI.
In this document we're going to use TCHAR like the Window.h header files do.
You can use the API without incurring any dependency on Memory Validator.
If Memory Validator is not installed on the machine the software runs on, nothing will happen.
This allows you to add the Memory Validator API to your software without need to have a separate build for use with Memory Validator.
For most use cases won't need to load the profiler, as the profiler will have been loaded when your launched your program from Memory Validator, or when you injected into your program using Inject or Wait For Application.
However if you're running your program from outside of Memory Validator and want to load the profiler from inside your program you can use mvLoadProfiler() to do that. You'll then need to call mvStartProfiler() to start it.
To start the profiler from your API code you need to call the function mvStartProfiler() from your code before you call any API functions. Ideally you should call this function as early in your program as possible.
If you prefer to start the profiler from the user interface or command line you can omit the mvStartProfiler() call. You can leave it present if you wish to start Memory Validator from your program.
You can name threads using the mvSetThreadName() function.
You can name threads using the mvSetHeapName() function.
You can turn data collection on and off using the mvSetCollect() function.
You can use mvGetCollect() to inspect the data collection status.
You can group many related allocations together by assigning them a tag tracker.
You do this by pushing a tag tracker on to the tag tracker stack.
Any allocations that happen when there are tag trackers on the stack are assigned to that tag tracker.
When you have finished with that tag tracker you can pop it off the stack.
This can be useful for clustering related database allocations, or related game allocations.
For example:
mvPushTracker(_T("Flowers"));
f = new Daffodil();
flowers.push_back(f);
f = new Rose();
flowers.push_back(f);
f = new Geranium();
flowers.push_back(f);
mvPopTracker();
Having configured "Flowers" as above, in the user interface in the various filtering options you can select Flowers in the tag tracker (or in the Statistics view) to see which Flowers are still allocated without seeing data for any other allocation.
You can also do this with a helpful class: svlDataTracker. When the class does out of scope the top of the tag tracker stack is popped.
You can push more than one tag tracker at a time.
{
svlDataTracker(_T("Plants"));
{
svlDataTracker(_T("Trees"));
t = new Oak(); // Trees tag tracker
trees.push_back(t);
t = new Sycamore(); // Trees tag tracker
trees.push_back(t);
t = new Cyrpress(); // Trees tag tracker
trees.push_back(t);
}
{
svlDataTracker(_T("Flowers"));
f = new Daffodil(); // Flowers tag tracker
flowers.push_back(f);
f = new Rose(); // Flowers tag tracker
flowers.push_back(f);
f = new Geranium(); // Flowers tag tracker
flowers.push_back(f);
}
g = new Grass(); // Plants tag tracker
}
str = new string("weebles wobble but they don't fall down"); // no tag tracker
You can place watermarks to identify locations in the stream of memory allocations being monitored.
Done carefully this can allow you to provide easy ways to check that particular parts of your application are behaving as expected.
For example you could place a watermark before a database transaction, and a watermark after a database transaction. Then either during a session, or at the end of the session (when you have the leak report) you can display all allocations between the two watermarks.
You can also place watermarks interactively, but automated watermark placement is much faster, and easier to place them in the correct place.
mvSetWatermarkEx(_T("Start purchase"));
if (processPurchase())
{
commitTransaction();
}
else
{
rollbackTransaction();
}
mvSetWatermarkEx(_T("End purchase"));
Having created two watermarks you can now configure various filtering options on many of Memory Validator's user interfaces to show you data before a watermark, after a watermark and between two watermarks.
If there is nothing shown between two watermarks it's because anything that was allocated between the creation of those two watermarks has been deallocated.