Rss Feed
Tweeter button
Facebook button
Technorati button
Reddit button
Myspace button
Linkedin button
Webonews button
Delicious button
Digg button
Flickr button
Stumbleupon button
Newsvine button

Category: Memory

Fix for FALSE positive memory leak report VS 2015 Update 1

By , December 18, 2015 12:39 pm

We’ve just released a V6.54 of C++ Memory Validator.

This contains a bug fix for FALSE positive memory leak reports when working with Release mode builds of programs built using Visual Studio 2015 Update 1.

Existing customers with valid software maintenance have been emailed about this release. The download is available from the customer login and also from the Software Updates menu in the software.

Share

Marmalade game SDK support

By , December 16, 2015 12:02 pm

We’ve recently added support for the Marmalade game SDK to C++ Memory Validator.

This article will show you how to configure a Marmalade project for use with C++ Memory Validator, how to setup C++ Memory Validator for use with Marmalade and how to launch a Marmalade game from C++ Memory Validator.

Configuring your project settings

To work with C++ Memory Validator you need to build the x86 Debug configuration and/or the x86 Release configuration of your Marmalade project using Visual Studio.

These configurations need to be built so that they create debug information and so that a PDB file containing debug information is created. The example projects that ship with Marmalade do not do this – you will need to edit them to make the linker stage create debug information.

Editing the compile stage debug information

marmalade-vs-compile


Editing the link stage debug information

marmalade-vs-linker


You must ensure that both compile and link stages have the correct settings set. If only compile or only link is set you will not get debugging symbols.

Debugging symbols are important for two reasons:

  • Without symbols C++ Memory Validator cannot find the Marmalade memory allocators and will not be able to track the Marmalade memory allocations your game makes.
  • Without symbols C++ Memory Validator will not be able to turn callstack addresses into class names, function names, filenames and line numbers.

Configuring C++ Memory Validator

In order to work correctly with Marmalade we need to make sure we’re only going to track the memory allocation your game makes with Marmalade and not any of the work that the Marmalade game engine is doing itself. We need to make a few simple changes to C++ Memory Validator.

  • Open the settings dialog. Click Reset. This will reset all C++ Memory Validator settings to the default.
  • Go to the Collect tab, disable the check boxes in the top two groups of check boxes, then enable the single Marmalade check box. The settings should look like shown below.
  • Click OK.

settings-collect-marmalade


Launching the game

To launch a Marmalade game with C++ Memory Validator we launch the Marmalade simulator and specify the game to run using the Marmalade -via command line argument.

If Marmalade is installed in c:\marmalade then the path to the simulator is

c:/marmalade/8.0/s3e\win32\s3e_simulator_release.exe

If an example game (shipped with Marmalade) is found at this location

c:\Marmalade\8.0\examples\GameTutorial\Lua\Stage9\build_temp\build_stage9_vc14\Stage9_vc14_release.via

then the command line is

-via:"c:\Marmalade\8.0\examples\GameTutorial\Lua\Stage9\build_temp\build_stage9_vc14\Stage9_vc14_release.via"

and the startup directory is

c:\Marmalade\8.0\examples\GameTutorial\Lua\Stage9\build_temp\build_stage9_vc14\

We leave the Application to monitor unchanged. It should have the same value as Application to launch.

This is how the launch dialog looks when you are launching this game.

launch-marmalade


Click Go! to launch the Marmalade game. C++ Memory Validator will monitor all memory allocations, reallocations and deallocations made via the s3eMalloc, s3eRealloc, s3eFree functions. Run your game as normal, then close your game. Wait for C++ Memory Validator to show you any leaks on the Memory tab. Additional statistics can be views on the Objects, Sizes, Timeline and Hotspots tabs.

Share

How to speed up Memory Validator by changing DbgHelp version

By , September 6, 2015 9:26 am

Recently we’ve had a few customers contact to tell us they have experienced a dramatic reduction in speed when using C++ Memory Validator.

We found this puzzling as we hadn’t really noticed this. We investigate and found that some parts of our code were hitting the disk a bit too much. To address this we implemented a buffered file read/write system so that we hit the disk once rather than many times. For our test case (which was a substantial program being monitored) this worked wonders. Performance improved enormously. Smiles all round.

But our customers still reported problems. This was puzzling. We started logging everything in one particular code path (which we knew was the problem). Nothing obvious. Next step, start timing all the logging. But just before we got to that we did a simple test. We iterated through each version of DbgHelp.dll that C++ Memory Validator can supply – if you remember we let you specify which Visual Studio version you used and we supply a version of DbgHelp.dll that ships and works for that (not all DbgHelp.dll are equal!).

Imagine our surprise when we found that DbgHelp.dll (6.11.1.404) shipped prior to Visual Studio 2013 are blazingly fast and the DbgHelp.dll we supply for use with Visual Studio 2013/2015 (6.3.9431.0) are slow. If you’re paying attention you’ll also notice the DbgHelp.dll version number has decreased rather than increased – ask Microsoft, we have no idea why they decreased the version number with more recent releases.

For now, until we can get a new release out to address this anomaly we recommend that you ignore choosing the Visual Studio you are using and deliberately choose Visual Studio 2012. This will select DbgHelp 6.11.1.404 and you should find the usual blazing speeds you are used to are restored.

To change the version of DbgHelp used, open the settings dialog, go to Symbol Lookup then change the version in the combo box. Click OK.

Any problems, as usual, please contact support.

Share

64 bit C++ software tool Beta Tests are complete.

By , January 9, 2014 1:33 pm

We recently closed the beta tests for the 64 bit versions of C++ Coverage Validator, C++ Memory Validator, C++ Performance Validator and C++ Thread Validator.

We launched the software on 2nd January 2014. A soft launch, no fanfare, no publicity. We just wanted to make the software available and then contact all the beta testers so that we could honour our commitments made at the start of the beta test.

Those commitments were to provide a free single user licence to any beta tester that provided feedback, usage reports, bugs reports, etc about the software. This doesn’t include anyone that couldn’t install the software because they used the wrong licence key!

We’ve written a special app here that we can use to identify all email from beta test participants and allow us to evaluate that email for beta test feedback criteria. It’s saved us a ton of time and drudge work even though writing this extension to the licence manager software took a few days. It was interesting using the tool and seeing who provided feedback and how much.

We’ve just sent out the licence keys and download instructions to all those beta testers that were kind enough to take the time to provide feedback, bug reports etc. to us. A few people went the extra mile. These people bombarded us with email containing huge bugs, trivial items and everything in between. Two of them, we were on the verge of flying out to their offices when we found some useful software that allowed to us to remotely debug their software. Special mentions go to:

Bengt Gunne (Mimer.com)
Ciro Ettorre (Mechworks.com)
Kevin Ernst (Bentley.com)

We’re very grateful for everyone taking part in the beta test. Thank you very much.

Why didn’t I get a free licence?

If you didn’t receive a free licence and you think you did provide feedback, please contact us. It’s always possible that a few people slipped through our process of identifying people.

Dang! I knew I should’ve provided feedback

If you didn’t provide us with any feedback, check your inbox. You’ll find a 50% off coupon for the tool that you tested.

Share

The nine types of memory leak

By , September 30, 2011 1:48 pm

Memory leaks affect all computer programs be they desktop applications, service applications or web services. For many trivial applications or applications with a very short application lifetime the odd memory leak is often not of significant importance and will go un-noticed. However for larger applications that use lots of memory or which need to run for a long time (for example web-servers) memory leaks are a serious problem.

Handle Leaks

This article is specifically talking about memory leaks. However handle leaks are just as serious. Not every item in this article has a corresponding handle leak equivalent. However some of the memory leaks shown do have corresponding handle leak equivalents. So if you are concerned about handle leaks, please read this article and just think about handles rather than memory. Most of the examples will apply.

The consequences of memory leaks?

  • Left unchecked memory leaks with ultimately result in the failure of the application to function when requests to allocate memory fail.
  • Memory leaks often mask other problems such as memory corruptions, buffer overruns and buffer underruns. When the leak is fixed these other problems often reveal themselves showing you that the application has more serious problems that also need to be addressed.

Why should you fix memory leaks?

  • Fixing memory leaks often reveals buffer overruns, buffer underruns, memory corruptions, calling functions on deleted objects (which will lead to indeterminate behaviour), multiple access to memory that was freed (incorrect memory access problems). Fixing these problems then results in an overall boost in application software quality, reliability and robustness.
  • Fixing memory leaks improves your application’s memory footprint allowing it to run for longer without errors and failures of operation. This in turn leads to greater user/customer satisfaction.

One proposed solution to memory leaks is to use garbage collection. Garbage collection removes the responsibility of deallocating memory from the programmer. Well, that is the theory. The reality is that garbage collected languages and technologies (.Net, C#, Java, Python, Ruby, etc) can all suffer from memory leaks caused by the programmer forgetting to set references to objects to NULL when they have finished with them. Garbage collection simply changes the cause of the memory leak from forgetting to deallocate the memory to forgetting to reset the reference to NULL. Either way the memory gets leaked. However the fix for deterministic memory leaks is often much easier to determine whereas for garbage collected memory leaks identifying where reset object references is not always so easy.

In this article we are concerned with deterministic memory leaks – the type of memory leak you may get when using a language such as C, C++, Delphi, Fortran, etc – non garbage collected allocations.

We will cover garbage collected memory leaks in another article.

How to deallocate memory.

You should always use the correct deallocator to deallocate memory allocated by an allocator. Array allocations should be matched with array deallocations and single object allocations should be matched with single object deallocations.

malloc free
calloc free
realloc free
_expand free
new delete
new [] delete []
HeapAlloc HeapFree
HeapReAlloc HeapFree
LocaAlloc LocalFree
GlobalAlloc GlobalFree
VirtualAlloc VirtualFree
SysAllocString SysFreeString
CoTaskMemAlloc CoTaskMemFree
CoTaskMemRealloc CoTaskMemFree

Memory leaks fall into one of several categories.

We have identified nine broad categories of memory leak. Some of them are variations of other memory leaks, often with different program scope. We are going outline them all here so that you are aware of them. We will also identify example solutions for each type of memory leak.

#1 Leaked temporary workspace.

This is memory that is allocated inside a function or class method and which is not deallocated before the function completes.

HANDLE createCommsHandle(DWORD	id)
{
	char	*name;
	HANDLE	handle = NULL;

	name = new char [100];
	if (name != NULL)
	{
		sprintf(name, "workstation%d", id);
		handle = createHandle(name);
	}

	return handle;
}

In the above function the memory allocated for the name variable is not deallocated after the call to createHandle().

Solution:

HANDLE createCommsHandle(DWORD	id)
{
	char	*name;
	HANDLE	handle = NULL;

	name = new char [100];
	if (name != NULL)
	{
		sprintf(name, "workstation%d", id);
		handle = createHandle(name);

		delete [] name;
	}

	return handle;
}

#2 Leaked data member

This is memory allocated for use by a class member, but which is not deallocated before the class object is destroyed.

class commsHandle
{
public:
	commsHandle();

	~commsHandle();

	void setName(char	*p_name);

	void createCommsHandle();

private:
	HANDLE	handle;
	char	*name;
};

commsHandle::commsHandle()
{
	name = NULL;
	handle = NULL;
}

commsHandle::~commsHandle()
{
	if (handle != NULL)
		CloseHandle(handle);
}

void commsHandle::setName(char	*p_name)
{
	size_t	len;

	len = strlen(p_name);
	name = new char [len + 1];
	if (name != NULL)
	{
		strcpy(name, p_name);
	}
}

void commsHandle::createCommsHandle()
{
	HANDLE	handle = NULL;

	handle = createHandle(name);

	return handle;
}

The above class has two problems:
#1 the destructor does not deallocate the memory allocated in setName().
#2 setName() does not deallocate the memory allocated in setName() prior to allocating a new value for name.

Solution:

commsHandle::~commsHandle()
{
	if (handle != NULL)
		CloseHandle(handle);

	if (name != NULL)
		delete [] name;

}

void commsHandle::setName(char	*p_name)
{
	if (name != NULL)
	{
		delete [] name;
		name = NULL;
	}

	size_t	len;

	len = strlen(p_name);
	name = new char [len + 1];
	if (name != NULL)
	{
		strcpy(name, p_name);
	}
}

#3 Leaked class static data member

This memory is allocated for use only by many functions of a class, but shared across all instances of that class.

class commsHandle
{
public:
	commsHandle();

	~commsHandle();

	static void setName(char	*p_name);

	void createCommsHandle();

private:
	HANDLE		handle;
	static char	*name;
};

commsHandle::commsHandle()
{
	handle = NULL;
}

commsHandle::~commsHandle()
{
	if (handle != NULL)
		CloseHandle(handle);
}

void commsHandle::setName(char	*p_name)
{
	size_t	len;

	len = strlen(p_name);
	name = new char [len + 1];
	if (name != NULL)
	{
		strcpy(name, p_name);
	}
}

void commsHandle::createCommsHandle()
{
	HANDLE	handle = NULL;

	handle = createHandle(name);

	return handle;
}

The above class has two problems:
#1 setName() does not deallocate the memory allocated in setName() prior to allocating a new value for name.
#2 there is no function to deallocate the memory allocated in setName() – it is not possible to call a function to cleanup this memory allocation.

Solution:

class commsHandle
{
public:
	commsHandle();

	~commsHandle();

	static void flushName();

	static void setName(char	*p_name);

	void createCommsHandle();

private:
	HANDLE		handle;
	static char	*name;
};

void commsHandle::flushName()
{
	if (name != NULL)
	{
		delete [] name;
		name = NULL;
	}
}

void commsHandle::setName(char	*p_name)
{
	flushName();

	size_t	len;

	len = strlen(p_name);
	name = new char [len + 1];
	if (name != NULL)
	{
		strcpy(name, p_name);
	}
}

With the above solution commsHandle::flushName() needs to be called during program shutdown (or at the end of main()).

#4 Leaked global memory

This memory is allocated for use by many functions and is not part of a class.

char *name;

void setName(char	*p_name)
{
	size_t	len;

	len = strlen(p_name);
	name = new char [len + 1];
	if (name != NULL)
	{
		strcpy(name, p_name);
	}
}

Solution:

char *name;


void flushName()
{
	if (name != NULL)
	{
		delete [] name;
		name = NULL;
	}
}


void setName(char	*p_name)
{

	flushName();

	size_t	len;

	len = strlen(p_name);
	name = new char [len + 1];
	if (name != NULL)
	{
		strcpy(name, p_name);
	}
}

With the above solution flushName() needs to be called during program shutdown (or at the end of main()).

#5 Leaked static memory

This memory is allocated soley for use by the function in which is is declared.

void doWork()
{
	static	char	*workspace = NULL;

	if (workspace == NULL)
	{
		workspace = new char [1000];
	}

	...
}

This is a similar leak to #4 except the scope of the memory is restricted to the function (or enclosing scope if declared at a deeper nesting level). The main problem with this allocation style is that there is no easy way to deallocate the memory if the memory is intended to be allocated only on the first call to the function (detected by the if (workspace == NULL) comparison).

Solution:

The solution is to provide an allocation function and a deallocation function. The allocation function getWorkSpace() is called from doWork() and the deallocation function flushWorkSpace() is called during program shutdown or at the end of main().


char *getWorkSpace(); // forward reference

void doWork()
{

	char	*workspace;

	workspace = getWorkSpace();


	...
}


static char *theWorkspace = NULL;

char *getWorkSpace()
{
	if (workSpace == NULL)
		theWorkSpace = new char [1000];

	return theWorkSpace;
}

void flushWorkSpace()
{
	delete [] theWorkSpace;
	theWorkSpace = NULL;
}


int main(int argc, char *argv[])
{
	...
	
	// end of program

	flushWorkSpace();

}

#6 Leaked worker object

This is when memory is allocated by function X and then passed to function Y to do a job and function X does not cleanup because it expects function Y to cleanup. A common case of this is when a function on one thread creates a data object to pass to a function on another thread.

// code on Thread 1

void processData(DWORD	id,
		 DWORD	tag,
		 DWORD	value)
{
	workerData	*wd;

	wd = new workerData(id, tag, value);
	if (wd != NULL)
	{
		addWorkerToQueue(wd);
	}	
}

void addWorkerToQueue(workerData	*wd)
{
	CCriticalSection	lock(§, TRUE);

	dataItems.Add(wd);
}

// code on Thread 2

void processQueue()
{
	CCriticalSection	lock(§, TRUE);
	DWORD			i, n;

	n = dataItems.GetSize();
	for(i = 0; i < n; i++)
	{
		workerData	*wd;

		wd = dataItems.GetAt(i);
		if (wd != NULL)
		{
			wd->doWork();
		}
	}

	dataItems.RemoveAll();
}

Solution:

The solution is to delete the worker objects once they have been use to do their work.

void processQueue()
{
	CCriticalSection	lock(§, TRUE);
	DWORD			i, n;

	n = dataItems.GetSize();
	for(i = 0; i < n; i++)
	{
		workerData	*wd;

		wd = dataItems.GetAt(i);
		if (wd != NULL)
		{
			wd->doWork();

			delete wd;

		}
	}

	dataItems.RemoveAll();
}

#7 Incorrect array delete memory leak

With C++ you can allocate arrays of objects and deallocate arrays of objects. The array form of delete is specified using [] and the non-array form of delete is specified without using [].

class memObj
{
public:
	memObj();

	~memObj();

	... // other functions

private:
	char	*data;
};

memObj::memObj()
{
	data = new [1000];
}

memObj::~memObj()
{
	delete [] data;
}

Consider this object definition that allocates memory in its constructor and deallocates memory in its destructor. On the face of it this does not look like it could leak memory. Well, it can if you allocate it in arrays and deallocate the array incorrectly…

	memObj	*array;

	array = new [10] memObj();

	delete array;

The above code allocates an array of 10 memObj objects then deallocates the array. The space for the array is deallocated but the destructor for each of the 10 memObj objects is only called for the first object. The other nine do not have their destructors called which means that each of the nine memObj objects leaks the memory it holds.

Solution:

	memObj	*array;

	array = new [10] memObj();

	delete [] array;

For instrinsic datatypes and simple objects that have no virtual functions and contain only intrinsic datatypes there may be no real damage by deallocating an array of objects using delete. But that leaves the door open to a memory leak should someone modify the object definition to be more complex or to have virtual functions. Thus you should always deallocate arrays using delete [] (even for intrinsics in case someone modifies the datatype of the intrinsic from say "int" to "complexNumber").

#8 Virtual object memory leak

Virtual functions are used in C++ to provide implementations of a function for an object that is derived from another object. For example an apple object would implement a different flavour() function than a pear object, both objects would be derived from a base class fruit. Objects that are derived from other objects must always have a virtual destructor in the base class. If the base class is not declared as virtual the destructors for the derived objects will not be called, resulting in memory leaks if those objects are meant to deallocate memory.

First we need to define a base class and some derived classes.

class train
{
public:
	train()

	~train();
};

train::train()
{
	...
}

train::~train()
{
	...
}

class steamTrain : public train
{
public:
	steamTrain();

	~steamTrain();

	void addFuel(int quantity);

private:
	coal	*fuel;
	DWORD	amount;
};

steamTrain::steamTrain()
{
	amount = 100;
	fuel = NULL;
	addFuel(amount);
}

steamTrain::~steamTrain()
{
	delete [] fuel;
}

void steamTrain::addFuel(int quantity)
{
	amount += quantity;
	delete [] fuel;
	fuel = new [amount] coal;
}

class electricTrain : public train
{
public:
	electricTrain();

	~electricTrain();

	void powerOn();

	void powerOff();

private:
	pantograph *power;
};

electricTrain::electricTrain()
{
	power = NULL;
}

electricTrain::~electricTrain()
{
	delete power;
}

void electricTrain::powerOn()
{
	delete power;
	power = new pantograph();
}

void electricTrain::powerOff()
{
	delete power;
	power = NULL;
}

Now if we use these object definitions…

	train	*steam = new steamTrain();
	train	*electric = new electricTrain();

	...

	delete steam;
	delete electric;

When the above code is executed the destructor for class train is called for both objects electric and steam. But the destructors for class steamTrain and class electricTrain is not called. This results in a memory leak of the coal and pantograph objects. The reason the destructors are not called is because the destructor for class train was not declared virtual.

Solution:

class train
{
public:
	train()

	virtual ~train();

};

#9 Calling the wrong deallocator

A form of memory leak we’ve seen a few times is caused by the wrong deallocator being used for a given allocator.

char *ptr;

ptr = new char [100];
free(ptr);

HLOCAL loc;

loc = LocalAlloc(LMEM_FIXED, 1000:
GlobalFree(loc);

When you do this different things can happen depending upon what the allocating function was and what the deallocating function is. Possible outcomes are:

  • Memory gets deallocated successfully! This can happen – if the implementation of delete calls free() then some calls to delete will succeed if the memory was allocated by malloc(). We do not recommend doing this. This relies upon implementation dependent details that may change with a future version of the compiler, or change between debug and release builds. This is also a serious impediment to writing portable code should you be writing for more than one operating system.
  • Memory does not get deallocated. Program execution continues as normal and no damage is done to the program.
  • Memory does not get deallocated. Program execution continues as normal but damage is done to heap datastructures in the program. This damage may lead to "random" crashes in your application some time later.
  • Memory does not get deallocated. Program crashes. When this happens you have a strong indicator something is wrong and you may well identify the calling of the wrong deallocator as the cause of the crash.

You should always deallocate using the documented deallocator and if applicable the correct form of array/single declaration (for new/delete and new []/delete []).

Additional types of memory leak

Some programming styles allocate memory once early in the program lifetime and deliberately never deallocate the memory.

static char *longLife = NULL;

// getLongLife called from other parts of the program

char *getLongLife()
{
	return longLife();
}

int main(int  argc,
	 char *argv[])
{
	longLife = new char [1000];

	doWork();
}

This is a one-shot memory allocation intended to last the entire program lifetime because the program authors think the memory may be useful at any stage in the application, including deep inside the program shutdown sequence.

This may happen for some multi-threaded applications where the memory is shared between many threads and for whatever reason the program authors do not think it wise to clean the memory up. One example of this was the lazy allocation of thread local data in earlier versions of Microsoft’s C runtime. The CRT made no attempt to cleanup the memory when the program exited. More recent versions of Microsoft’s CRT have a different behaviour.

Other reasons can be creating workspace for debugging tools injected into a program where the tool expects to try to report data as far into program shutdown as it can go. As such the tool will want its workspace available until the operating system pulls the rug out from under it (which in our experience, is pretty much what happens, if you can fool the OS into letting your DLL last past its DllMain when it would normally be closed you won’t get a second notification that your DLL is going to be killed).

In our experience, although it may be convenient to have a programming style where you can just allocate a whole-application-lifetime object and not-deallocate it this programming style hinders the use of memory debugging tools (by all vendors, not just ourselves) as this whole-application-lifetime object will always be reported as a leak (because it never gets deallocated). That in turn means your memory-leak fix team need to be aware of this object (these objects!) and ignore it. Depending upon your application this can be a waste of developer time.

Much better and tidier to deallocate all memory allocations in every circumstance you can make it happen.

Share

Command line support for .Net services and ASP.Net

By , September 29, 2011 3:59 pm

Today we have released updated versions of our software tools for .Net, .Net Coverage Validator, .Net Memory Validator and .Net Performance Validator.

The updates to each tool add support for monitoring .Net services and ASP.Net processes when working with the tool from the command line. This allows you to, for example, control the tool from batch files and easy create large suites of tests that you can run and control from batch files or using other scripting technologies. This command line support builds on the already existing command line support in each tool for working with .Net desktop appplications. For information on existing command line options for each tool please see the help file that ships with each tool.

I’m going to outline the new command line options for each tool and provide some basic examples of how you might use these options with each tool. Each tool has been given the same basic options, with each tool getting some additional options specific to that tool.

.Net Coverage Validator

  • -serviceName fileName

    The -serviceName option is used to specify which service .Net Coverage Validator should monitor. The filename argument should be quoted if the filename contains spaces.

    -serviceName c:\path\myservice.exe
    -serviceName "c:\path with spaces\myservice.exe"
    
  • -urlToVisit url

    The -urlToVisit option specifies the web page that should be opened by the web browser when working with ASP.Net web servers.

    -urlToVisit http://localhost/myTestPage.aspx
    -urlToVisit "http://localhost/myTestPage.aspx"
    
  • -aspNetName filename

    The -aspNetName option is used to specify the ASP.Net process that is used by IIS. The filename argument should be quoted if the filename contains spaces.

    -aspNetName c:\windows\Microsoft.Net\Framework\v4.0.30319\aspnet_wp.exe
    -aspNetName "c:\windows\Microsoft.Net\Framework\v4.0.30319\aspnet_wp.exe"
    

    The value specified should be the value that you would specify if you used the .Net Coverage Validator interface to work with ASP.Net applications.

  • -webRoot directoryname

    The -webRoot option is used to specify the web root for this ASP.Net process. The directoryname argument should be quoted if the filename contains spaces.

    -webRoot c:\inetpub\wwwroot
    -webRoot "c:\inetpub\wwwroot"
    
  • -webBrowser filename

    The -webBrowser option is used to specify which web browser to use to open the web page if the user has chosen to specify a particular web browser. This option is used when the -aspNetWeb option specifies to use a specific web browser. The filename argument should be quoted if the filename contains spaces.

    -webBrowser c:\mozilla\firefox.exe
    -webBrowser "c:\program files\internet explorer\iexplore.exe"
    
  • -coverageDirectory directoryname

    The -coverageDirectory option specifies the directory .Net Coverage Validator will use to communicate with the GUI if security privileges do not allow named pipes and shared memory usage. The directoryname argument should be quoted if the filename contains spaces.

    -coverageDirectory c:\temp
    
  • -aspNetWeb default|user|specific

    The -aspNetWeb option is used to specify which web browser will be used to open the web page you have specified.

    The options are:

    default Use the default web browser.
    user The user will open a web browser themselves.
    specific Use a web browser identified by a filepath. Use in conjunction with -webBrowser option.
    -aspNetWeb default
    -aspNetWeb user
    -aspNetWeb specfic
    
  • -aspNetDelay integer

    The -aspNetDelay option is used to specify how long .Net Coverage Validator will wait for IIS to reset and restart itself. The delay is specified in milliseconds.

    -aspNetDelay 5000
    

Working with .Net services

This example shows how to use .Net Coverage Validator with a .Net service.

dnCoverageValidator.exe -serviceName E:\WindowsService\bin\Debug\WindowsService.exe 
-coverageDirectory c:\test\coverage -saveSession "c:\test results\testbed.dncvm" 
-hideUI
  • -serviceName E:\WindowsService\bin\Debug\WindowsService.exe

    This specifies the service to monitor. The service must be started after .Net Coverage Validator has been instructed to monitor the service.

  • -coverageDirectory c:\test\coverage

    This specifies the directory .Net Coverage Validator will use to communicate with the GUI if security privileges do not allow named pipes and shared memory usage.

  • -saveSession “c:\test results\testbed.dncvm”

    This specifies that after the application finishes the session should be saved in the file c:\test results\testbed.dncvm.

  • -hideUI

    This specifies that the user interface should not be displayed during the test. When the target service closes .Net Coverage Validator will close.

Working with ASP.Net

This example shows how to use .Net Coverage Validator with ASP.Net.

dnCoverageValidator.exe -urlToVisit http://localhost/testWebApp.aspx 
-aspNetName c:\windows\Microsoft.Net\Framework\v4.0.30319\aspnet_wp.exe 
-aspNetWeb default -aspNetDelay 5000 -webRoot c:\inetput\wwwroot 
-coverageDirectory c:\test\coverage -saveSession "c:\test results\testbed.dncvm" 
-hideUI
  • -urlToVisit http://localhost/testWebApp.aspx

    This specifies the web page that will be opened when working with ASP.Net

  • -aspNetName c:\windows\Microsoft.Net\Framework\v4.0.30319\aspnet_wp.exe

    This specifies the ASP.Net worker process that IIS will start.

  • -aspNetWeb default

    This specifies that the system defined web browser will be used to open the web page.

  • -aspNetDelay 5000

    This specifies a delay of 5 seconds to allow the IIS webserver to restart.

  • -webRoot c:\inetput\wwwroot

    This specifies the web root of the IIS web server.

  • -coverageDirectory c:\test\coverage

    This specifies the directory .Net Coverage Validator will use to communicate with the GUI if security privileges do not allow named pipes and shared memory usage.

  • -saveSession “c:\test results\testbed.dncvm”

    This specifies that after the application finishes the session should be saved in the file c:\test results\testbed.dncvm.

  • -hideUI

    This specifies that the user interface should not be displayed during the test. When the target service closes .Net Coverage Validator will close.

.Net Memory Validator

  • -collectData

    The -collectData option causes .Net Memory Validator to collect memory allocation events until the user chooses to disable data collection from the user interface.

    -collectData
    
  • -doNotCollectData

    The -doNotCollectData option causes .Net Memory Validator to ignore memory allocation events until the user chooses to enable data collection from the user interface.

    -doNotCollectData
    
  • -serviceName fileName

    The -serviceName option is used to specify which service .Net Memory Validator should monitor. The filename argument should be quoted if the filename contains spaces.

    -serviceName c:\path\myservice.exe
    -serviceName "c:\path with spaces\myservice.exe"
    
  • -urlToVisit url

    The -urlToVisit option specifies the web page that should be opened by the web browser when working with ASP.Net web servers.

    -urlToVisit http://localhost/myTestPage.aspx
    -urlToVisit "http://localhost/myTestPage.aspx"
    
  • -aspNetName filename

    The -aspNetName option is used to specify the ASP.Net process that is used by IIS. The filename argument should be quoted if the filename contains spaces.

    -aspNetName c:\windows\Microsoft.Net\Framework\v4.0.30319\aspnet_wp.exe
    -aspNetName "c:\windows\Microsoft.Net\Framework\v4.0.30319\aspnet_wp.exe"
    

    The value specified should be the value that you would specify if you used the .Net Memory Validator interface to work with ASP.Net applications.

  • -webRoot directoryname

    The -webRoot option is used to specify the web root for this ASP.Net process. The directoryname argument should be quoted if the filename contains spaces.

    -webRoot c:\inetpub\wwwroot
    -webRoot "c:\inetpub\wwwroot"
    
  • -webBrowser filename

    The -webBrowser option is used to specify which web browser to use to open the web page if the user has chosen to specify a particular web browser. This option is used when the -aspNetWeb option specifies to use a specific web browser. The filename argument should be quoted if the filename contains spaces.

    -webBrowser c:\mozilla\firefox.exe
    -webBrowser "c:\program files\internet explorer\iexplore.exe"
    
  • -aspNetWeb default|user|specific

    The -aspNetWeb option is used to specify which web browser will be used to open the web page you have specified.

    The options are:

    default Use the default web browser.
    user The user will open a web browser themselves.
    specific Use a web browser identified by a filepath. Use in conjunction with -webBrowser option.
    -aspNetWeb default
    -aspNetWeb user
    -aspNetWeb specfic
    
  • -aspNetDelay integer

    The -aspNetDelay option is used to specify how long .Net Memory Validator will wait for IIS to reset and restart itself. The delay is specified in milliseconds.

    -aspNetDelay 5000
    

Working with .Net services

This example shows how to use .Net Memory Validator with a .Net service.

dnMemoryValidator.exe -serviceName E:\WindowsService\bin\Debug\WindowsService.exe 
-saveSession "c:\test results\testbed.dnmvm" -hideUI
  • -serviceName E:\WindowsService\bin\Debug\WindowsService.exe

    This specifies the service to monitor. The service must be started after .Net Memory Validator has been instructed to monitor the service.

  • -saveSession “c:\test results\testbed.dnmvm”

    This specifies that after the application finishes the session should be saved in the file c:\test results\testbed.dnmvm.

  • -hideUI

    This specifies that the user interface should not be displayed during the test. When the target service closes .Net Memory Validator will close.

Working with ASP.Net

This example shows how to use .Net Memory Validator with ASP.Net.

dnMemoryValidator.exe -urlToVisit http://localhost/testWebApp.aspx 
-aspNetName c:\windows\Microsoft.Net\Framework\v4.0.30319\aspnet_wp.exe 
-aspNetWeb default -aspNetDelay 5000 -webRoot c:\inetput\wwwroot 
-saveSession "c:\test results\testbed.dnmvm" -hideUI
  • -urlToVisit http://localhost/testWebApp.aspx

    This specifies the web page that will be opened when working with ASP.Net

  • -aspNetName c:\windows\Microsoft.Net\Framework\v4.0.30319\aspnet_wp.exe

    This specifies the ASP.Net worker process that IIS will start.

  • -aspNetWeb default

    This specifies that the system defined web browser will be used to open the web page.

  • -aspNetDelay 5000

    This specifies a delay of 5 seconds to allow the IIS webserver to restart.

  • -webRoot c:\inetput\wwwroot

    This specifies the web root of the IIS web server.

  • -saveSession “c:\test results\testbed.dnmvm”

    This specifies that after the application finishes the session should be saved in the file c:\test results\testbed.dnmvm.

  • -hideUI

    This specifies that the user interface should not be displayed during the test. When the target service closes .Net Memory Validator will close.

.Net Performance Validator

  • -collectData

    The -collectData option causes .Net Performance Validator to collect memory allocation events until the user chooses to disable data collection from the user interface.

    -collectData
    
  • -doNotCollectData

    The -doNotCollectData option causes .Net Performance Validator to ignore memory allocation events until the user chooses to enable data collection from the user interface.

    -doNotCollectData
    
  • -collectFunctionTimes

    The -collectFunctionTimes option causes .Net Performance Validator to collect timing information for functions in the application/service/ASP.Net webserver.

    -collectFunctionTimes
    
  • -collectLineTimes
    The -collectLinesTimes option causes .Net Performance Validator to collect timing information for lines in the application/service/ASP.Net webserver.

    -collectLineTimes
    
  • -doNotCollectFunctionTimes
    The -doNotCollectFunctionTimes option causes .Net Performance Validator not to collect timing information for functions in the application/service/ASP.Net webserver.

    -doNotCollectFunctionTimes
    
  • -doNotCollectLineTimes
    The -doNotCollectLinesTimes option causes .Net Performance Validator not to collect timing information for lines in the application/service/ASP.Net webserver.

    -doNotCollectLineTimes
    
  • -serviceName fileName

    The -serviceName option is used to specify which service .Net Performance Validator should monitor. The filename argument should be quoted if the filename contains spaces.

    -serviceName c:\path\myservice.exe
    -serviceName "c:\path with spaces\myservice.exe"
    
  • -urlToVisit url

    The -urlToVisit option specifies the web page that should be opened by the web browser when working with ASP.Net web servers.

    -urlToVisit http://localhost/myTestPage.aspx
    -urlToVisit "http://localhost/myTestPage.aspx"
    
  • -aspNetName filename

    The -aspNetName option is used to specify the ASP.Net process that is used by IIS. The filename argument should be quoted if the filename contains spaces.

    -aspNetName c:\windows\Microsoft.Net\Framework\v4.0.30319\aspnet_wp.exe
    -aspNetName "c:\windows\Microsoft.Net\Framework\v4.0.30319\aspnet_wp.exe"
    

    The value specified should be the value that you would specify if you used the .Net Performance Validator interface to work with ASP.Net applications.

  • -webRoot directoryname

    The -webRoot option is used to specify the web root for this ASP.Net process. The directoryname argument should be quoted if the filename contains spaces.

    -webRoot c:\inetpub\wwwroot
    -webRoot "c:\inetpub\wwwroot"
    
  • -webBrowser filename

    The -webBrowser option is used to specify which web browser to use to open the web page if the user has chosen to specify a particular web browser. This option is used when the -aspNetWeb option specifies to use a specific web browser. The filename argument should be quoted if the filename contains spaces.

    -webBrowser c:\mozilla\firefox.exe
    -webBrowser "c:\program files\internet explorer\iexplore.exe"
    
  • -profilerDirectory directoryname

    The -profilerDirectory option specifies the directory .Net Performance Validator will use to communicate with the GUI if security privileges do not allow named pipes and shared memory usage. The directoryname argument should be quoted if the filename contains spaces.

    -profilerDirectory c:\temp
    
  • -aspNetWeb default|user|specific

    The -aspNetWeb option is used to specify which web browser will be used to open the web page you have specified.

    The options are:

    default Use the default web browser.
    user The user will open a web browser themselves.
    specific Use a web browser identified by a filepath. Use in conjunction with -webBrowser option.
    -aspNetWeb default
    -aspNetWeb user
    -aspNetWeb specfic
    
  • -aspNetDelay integer

    The -aspNetDelay option is used to specify how long .Net Performance Validator will wait for IIS to reset and restart itself. The delay is specified in milliseconds.

    -aspNetDelay 5000
    

Working with .Net services

This example shows how to use .Net Performance Validator with a .Net service.

dnPerformanceValidator.exe -serviceName E:\WindowsService\bin\Debug\WindowsService.exe 
-profilerDirectory c:\test\profiler -saveSession "c:\test results\testbed.dnpvm" 
-hideUI
  • -serviceName E:\WindowsService\bin\Debug\WindowsService.exe

    This specifies the service to monitor. The service must be started after .Net Performance Validator has been instructed to monitor the service.

  • -profilerDirectory c:\test\profiler

    This specifies the directory .Net Performance Validator will use to communicate with the GUI if security privileges do not allow named pipes and shared memory usage.

  • -saveSession “c:\test results\testbed.dnpvm”

    This specifies that after the application finishes the session should be saved in the file c:\test results\testbed.dnpvm.

  • -hideUI

    This specifies that the user interface should not be displayed during the test. When the target service closes .Net Performance Validator will close.

Working with ASP.Net

This example shows how to use .Net Performance Validator with ASP.Net.

dnPerformanceValidator.exe -urlToVisit http://localhost/testWebApp.aspx 
-aspNetName c:\windows\Microsoft.Net\Framework\v4.0.30319\aspnet_wp.exe 
-aspNetWeb default -aspNetDelay 5000 -webRoot c:\inetput\wwwroot 
-profilerDirectory c:\test\profiler -saveSession "c:\test results\testbed.dnpvm" 
-hideUI
  • -urlToVisit http://localhost/testWebApp.aspx

    This specifies the web page that will be opened when working with ASP.Net

  • -aspNetName c:\windows\Microsoft.Net\Framework\v4.0.30319\aspnet_wp.exe

    This specifies the ASP.Net worker process that IIS will start.

  • -aspNetWeb default

    This specifies that the system defined web browser will be used to open the web page.

  • -aspNetDelay 5000

    This specifies a delay of 5 seconds to allow the IIS webserver to restart.

  • -webRoot c:\inetput\wwwroot

    This specifies the web root of the IIS web server.

  • -profilerDirectory c:\test\profiler

    This specifies the directory .Net Performance Validator will use to communicate with the GUI if security privileges do not allow named pipes and shared memory usage.

  • -saveSession “c:\test results\testbed.dnpvm”

    This specifies that after the application finishes the session should be saved in the file c:\test results\testbed.dnpvm.

  • -hideUI

    This specifies that the user interface should not be displayed during the test. When the target service closes .Net Performance Validator will close.

Share

How to prevent a memory tool from monitoring your C/C++ allocations

By , July 10, 2010 10:53 am

A little known fact is that the Microsoft C Runtime (CRT) has a feature which allows some allocations (in the debug runtime) to be tagged with flags that causes these allocations to be ignored by the built in memory tracing routines. A good memory allocation tool will also use these flags to determine when to ignore memory allocations – thus not reporting any allocations that Microsoft think should remain hidden.

A customer problem

The inspiration for this article was a customer reporting that Memory Validator was not reporting any allocations in a particular DLL of his mixed mode .Net/native application. The application was interesting in that it was a combination of C#, C++ written with one version of Visual Studio and some other DLLs also written in C++ with another version of Visual Studio. Only the memory for one of the DLLs was not being reported by Memory Validator and the customer wanted to know why and could we please fix the problem?

After some investigation we found the problem was a not with Memory Validator but with the DLL in question making a call to _CrtSetDbgFlag(0); which turned off all memory tracking for that DLL. Memory Validator honours the memory tracking flags built into Visual Studio and thus did not report these memory allocations. Armed with this information the customer did some digging into their code base and found that someone had deliberately added this call into their code. Removing the call fixed the problem.

The rest of this article explains how Microsoft tags data to be ignored and what flags are used to control this process.

Why does Microsoft mark these allocation as ignore?

The reason for this is that these allocations are for internal housekeeping and sometimes also for one-off allocations that will exist until the end of the application lifetime. Such allocations could show up as memory leaks at the end of the application – that would be misleading as they were intended to persist. Better to mark them as “ignore” and not report them during a memory leak report.

Microsoft debug CRT header block

Microsoft’s debug CRT prefixes each allocation with a header block. That header block looks like this:

#define nNoMansLandSize 4

typedef struct _CrtMemBlockHeader
{
    struct _CrtMemBlockHeader * pBlockHeaderNext;
    struct _CrtMemBlockHeader * pBlockHeaderPrev;
    char *                      szFileName;
    int                         nLine;
#ifdef _WIN64
    /* These items are reversed on Win64 to eliminate gaps in the struct
     * and ensure that sizeof(struct)%16 == 0, so 16-byte alignment is
     * maintained in the debug heap.
     */
    int                         nBlockUse;
    size_t                      nDataSize;
#else  /* _WIN64 */
    size_t                      nDataSize;
    int                         nBlockUse;
#endif  /* _WIN64 */
    long                        lRequest;
    unsigned char               gap[nNoMansLandSize];
    /* followed by:
     *  unsigned char           data[nDataSize];
     *  unsigned char           anotherGap[nNoMansLandSize];
     */
} _CrtMemBlockHeader;

How does Microsoft tag an allocation as ignore?

When the CRT wishes an allocation to be ignored for memory tracking purposes, six values in the debug memory allocation header for each allocation are set to specific values.

Member Value #define
nLine 0xFEDCBABC IGNORE_LINE
nBlockUse 0x3 IGNORE_BLOCK
lRequest 0x0 IGNORE_REQ
szFileName NULL
pBlockHeaderNext NULL
pBlockHeaderPrev NULL

The Microsoft code goes out of its way to ensure no useful information can be gained from the header block for these ignored items.

When we first created MV we noticed that items marked as ignored should be ignored, otherwise you can end up with FALSE positive noise reported at the end of a memory debugging session due to the internal housekeeping of MFC/CRT.

How can you use this information in your application?

Microsoft also provides some flags which you can control which allows you to influence if any memory is reported as leaked. This is in addition to the CRT marking its own allocations as “ignore”. You can set these flags using the _CrtSetDbgFlag(int); function.

The following flags can be passed to _CrtSetDbgFlag() in any combination.

Flag Default Meaning
_CRTDBG_ALLOC_MEM_DF On On: Enable debug heap allocations and use of memory block type identifiers.
_CRTDBG_CHECK_ALWAYS_DF Off On: Call _CrtCheckMemory at every allocation and deallocation request. (Very slow!)
_CRTDBG_CHECK_CRT_DF Off On: Include _CRT_BLOCK types in leak detection and memory state difference operations.
_CRTDBG_DELAY_FREE_MEM_DF Off Keep freed memory blocks in the heap’s linked list, assign them the _FREE_BLOCK type, and fill them with the byte value 0xDD. CAUTION! Using this option will use lots of memory.
_CRTDBG_LEAK_CHECK_DF Off ON: Perform automatic leak checking at program exit via a call to _CrtDumpMemoryLeaks and generate an error report if the application failed to free all the memory it allocated.

How do I disable memory tracking for the CRT?

If you call _CrtSetDbgFlag(0); any memory allocated after that point will not be tracked.

With the above settings, all blocks are marked as ignore. You can see the code for this in the Microsoft C runtime.

The code that marks the block as “ignore” is at line 404 in dbgheap.c in the Microsoft C runtime (also used by MFC). When your code arrives here, nBLockUse == 1 and _crtDbgFlag == 0.

dbgheap.c line 404 (line number will vary with Visual Studio version)
                if (_BLOCK_TYPE(nBlockUse) != _CRT_BLOCK &&
                     !(_crtDbgFlag & _CRTDBG_ALLOC_MEM_DF))
                     fIgnore = TRUE;

This sets fIgnore to TRUE. From this point onwards the memory tracking code ignores the memory and sets the values mentioned above in the memory block header.

Default values

The default value for _crtDbgFlag is set elsewhere in the Microsoft code with this line:

extern "C"
int _crtDbgFlag = _CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_DEFAULT_DF;
Share

How to replace IsBadReadPtr?

By , May 26, 2010 12:45 pm

The Microsoft Win32 API contains various functions that look useful at first sight but which have now become regarded as a pariahs. A good example of this is the IsBadReadPtr() function.

Under the hood this function uses structured exception handling to catch any exceptions that are thrown when the memory location read. If an exception is thrown the function returns TRUE, otherwise FALSE. So far so good.

So what could be wrong with that? A simplistic or naive interpretation would be “nothing”. But that ignores the fact that the callstacks of your application threads grow “on-demand”. This is done to avoid committing the full (default) 1MB upfront for each thread. This places a lower demand on application virtual memory and provides slightly faster startup for each thread. To allow each thread to grow on demand the stack has guard pages, which if you try to access them cause a guard page exception to be thrown which the OS handles gracefully, extends your stack space an appropriate amount and then returns execution to your application.

The problem with IsBadReadPtr() is that the exception handler inside IsBadReadPtr() eats the exception and thus the OS will not see it. So for the case where you end up using IsBadReadPtr() on a guard page you break the on-demand stack extension mechanism.

Raymond Chen of Microsoft has written a passionate post on this topic.

Raymond (and a few other folks) say that you should never use IsBadReadPtr(). I think thats a bit strong.

There are a few occasions where you may know what the datastructure is but you also know that it may have various memory protections on it. Such a case is when inspecting a DLL. Various parts are readonly. We have found during the last 10 years of writing tools like Memory Validator that it is not uncommon for a DLL loaded by LoadLibrary() to have memory protections on parts of the DLL that you don’t expect. We can’t control what DLLs our customer’s applications choose to load, so we have to handle all eventualities. We can’t just allow a crash to happen because we read a data location (in a customer DLL) that should be valid but isn’t.

Its also worth noting that the members of the team that wrote Boundschecker also came to the same conclusion and also tested certain DLL headers this way. You can find such code examples in the BugSlayer column in issues of Microsoft Systems Journal (MSJ) before it morphed into MSDN magazine.

One argument would be “Put an exception handler around it. Its an exceptional condition, handle it that way”.

The problem with that is sometimes that breaks the flow of the code and causes all manner of problems with the inability to mix C++ objects and SEH in the same function. Sometimes its much easier and simpler just to test for readability and abandon the function if you encounter one of these unusually constructed DLLs.

We are not advocating that you routinely use IsBadReadPtr() to hide the fact that you don’t know which objects to free, so you just call free on anything that passes IsBadReadPtr(). If you do that you will end up with exactly the problems that Raymond Chen describes.

But for the case where you do want IsBadReadPtr() functionality but you don’t want to use IsBadReadPtr(), what do you do? Here are drop in replacements for IsBadReadPtr() and IsBadWritePtr() that will not affect guard pages etc.

int isNotOKToReadMemory(void    *ptr,
                        DWORD   size)
{
	SIZE_T                          dw;
	MEMORY_BASIC_INFORMATION	mbi;
	int                             ok;

	dw = VirtualQuery(ptr, &mbi, sizeof(mbi));
	ok = ((mbi.Protect & PAGE_READONLY) ||
		  (mbi.Protect & PAGE_READWRITE) ||
		  (mbi.Protect & PAGE_WRITECOPY) ||
		  (mbi.Protect & PAGE_EXECUTE_READ) ||
		  (mbi.Protect & PAGE_EXECUTE_READWRITE) ||
		  (mbi.Protect & PAGE_EXECUTE_WRITECOPY));

	// check the page is not a guard page

	if (mbi.Protect & PAGE_GUARD)
		ok = FALSE;
	if (mbi.Protect & PAGE_NOACCESS)
		ok = FALSE;

	return !ok;
}

int isNotOKToWriteMemory(void   *ptr,
                         DWORD  size)
{
	SIZE_T                          dw;
	MEMORY_BASIC_INFORMATION	mbi;
	int                             ok;

	dw = VirtualQuery(ptr, &mbi, sizeof(mbi));
	ok = ((mbi.Protect & PAGE_READWRITE) ||
		  (mbi.Protect & PAGE_WRITECOPY) ||
		  (mbi.Protect & PAGE_EXECUTE_READWRITE) ||
		  (mbi.Protect & PAGE_EXECUTE_WRITECOPY));

	// check the page is not a guard page

	if (mbi.Protect & PAGE_GUARD)
		ok = FALSE;
	if (mbi.Protect & PAGE_NOACCESS)
		ok = FALSE;

	return !ok;
}

Remember: Use with caution, use sparingly and only if you need to. If you are routinely using IsBadReadPtr() or an equivalent to avoid keeping track of which data you should or should not use, you should think again about your software design.

Share

Monitoring memory use in a JNI DLL called from Java

By , May 8, 2010 1:35 pm

Java is a garbage collected language that allows you to extend the language with code written in C and C++.

Given that the extensions are written in C or C++ the normal tools for monitoring Java memory usage will not report the C/C++ memory usage. So how do you monitor the memory usage of these JNI extensions when called from Java? This article is going to explain how to do this task.

Building an example JNI test

The first thing to do is to create an example to work with. The post Creating a JNI example for testing describes how to create a JNI example (both Java code and JNI C/C++ code, with downloadable source and project files). Please download the example code and build the example.

Monitoring JNI Memory

Monitoring memory in JNI extensions is straightforward. Java programs are executed by running a Java Virtual Machine (JVM). These are typically named java.exe, javaw.exe, jre.exe, jrew.exe. We can just launch java.exe with a C/C++ memory leak detection software tool and monitor the results. For this example we are going to monitor java with C++ Memory Validator. The image below shows the launch dialog (note if you are using Memory Validator for the first time you will be using the launch wizard, which is slightly different)

Memory Validator launch dialog showing launch of Java application

Items to note:

  • Application is set to the path to java.exe. C:\Program Files (x86)\Java\jdk1.5.0_07\bin\java.exe
  • Arguments is set to the name of the class to execute. Main
  • Startup directory is set to the directory containing the class to execute (and the native DLL to monitor). E:\om\c\memory32\testJavaJNI
  • If you wish to set the CLASSPATH you can set it in the Environment Variables part of the launch dialog. If you do not set the CLASSPATH here (as in this example) the CLASSPATH will be taken from the inherited environment variables of Memory Validator’s environment. For this example CLASSPATH is set in the global environment variables and thus does not need to be set on the launch dialog.

Click Go! to start the Java program. Java is started, Memory Validator monitors the application and records all memory allocations and deallocations. Any memory not deallocated by the end of the program is a leak.

JNI Leaks with no filtering

As you can see from the screenshot above, there is a quite a bit of memory left over after a simple run of this example Java program which does very little except load a native extension that prints Hello World! twice and deliberately leaks one 20 byte chunk of memory. The example image indicates there are 857 items, some of which are handles, the remainder C/C++ memory allocations. There are 3493 events. The memory leak we are interested in occurs at event 2985.

Clearly this is inefficient. To find memory leaks in your code you are going to have to wade through all the noise of the memory allocations made by Java and the JVM. There must be a better way!

There is. We’ll focus only on the native DLL that prints the Hello World! messages. Open the settings dialog and go to the Hooked DLLs section.

Setting up DLL filters to focus on the JNI DLL

  • Select the second radio box to indicate that only the DLLs we list will be monitored.
  • Now click Add Module… and select the HelloWorldImp.dll.
  • Click OK.

Memory Validator is now configured to monitor only HelloWorldImp.dll for memory and handle allocations.
Relauch the java application with these new settings.

JNI Leaks with DLL filtering

As you can see from the picture above much less data is collected. A total of 54 events compared to the previous session’s 3493 events. This is much more managable.

The list of items Memory Validator reports for this run contains only 11 events. This reduced amount makes it very easy to identify errors in the DLL.

  • 8 events are DLL loads (MV always reports DLL loads regardless of settings)
  • A one time, per-thread, buffer allocation inside printf
  • A memory leak that is deliberately present in the example JNI code
  • The final event is the status information for the application at the end of its run

If you don’t wish to see the DLL loads you can filter them out with a global, session or local filter.

Detail view of source code of memory leak in JNI code

The image above shows the source code of the location of the leaking memory in the JNI extension.

Conclusion

Monitoring memory allocations in JNI Dlls called from Java is a straightforward task.

Things to remember:

  • Ensure your JNI DLL is compiled with debugging information and linked with debugging information.
  • Ensure your JNI DLL debug information is present (put the PDB file in the same directory as the DLL).
  • Ensure your CLASSPATH is set correctly so that when Memory Validator starts your Java application the correct CLASSPATH is used.
Share

What is the difference between a page and a paragraph?

By , March 8, 2010 11:40 am

In the real world we all know that pages contain paragraphs and that paragraphs are full of sentences created from words.

In the world of Microsoft Windows Operating Systems it is somewhat different – paragraphs contain pages!

In this article I’m to going to explain what a page is and what a paragraph is and how they relate to each other and why this information can be useful helping to identify and resolve certain memory related bugs.

Virtual Memory Pages
A virtual memory page is the smallest unit of memory that can be mapped by the CPU. In the case of 32 bit x86 processors such as the Intel Pentium and AMD Athlon, a page is 4Kb. When you make a call to VirtualProtect() or VirtualQuery() you will be setting or querying the memory protection for sizes that are multiples of a page.

The size of a page may vary from CPU type to CPU type. For example a 64 bit x86 CPU will have a page size of 8Kb.

You can determine the size of a page by calling GetSystemInfo() and reading the SYSTEM_INFO.dwPageSize value.

Virtual Memory Paragraphs
A virtual memory paragraph is the minimum amount of memory that can be commited/reserved using the VirtualAlloc() call. On 32 bit x86 CPUs this value is 64Kb (0x00010000). If you have ever used the debugger and looked at the load addresses of DLLs in the Modules list you may have noticed that DLLs always load on 64Kb boundaries. This is the reason – the area a DLL is loaded into is initialised by a call to VirtualAlloc to reserve the memory prior to the DLL being loaded.

Loaded Modules

You can determine the size of a paragraph by calling GetSystemInfo() and reading the SYSTEM_INFO.dwAllocationGranularity value.

Given these values, you can see that (on 32 bit 86 systems) a virtual memory paragraph is composed of 16 virtual memory pages.

How can I use this information?
If you are using VirtualAlloc() it is important to know the granularity at which the allocations will be returned. This is the size of a paragraph. This information is fundamental in deciding how you would implement a custom heap. You know there are fixed boundaries at which your data can exist. You can enumerate the list of possible paragraph locations very quickly (there are 32,768 possible locations in a 2GB space, as opposed to 2 billion locations if the paragraph could start anywhere).

Custom heaps
If you are writing a custom heap, a key indicator to keep track of is memory fragmentation and memory utilisation. Knowing your paragraph and page sizes you can inspect how each page and each paragraph of memory are used by the application and the custom heap to determine if there is wastage, what wastage there is and what form the wastage takes. This information could lead you to modify your heap algorithm to use pages differently to reduce fragmentation. See Delete memory 5 times faster for one simple technique, using HeapAlloc, the same principles apply here.

Loading large data files
Another use for this information is finding out why a certain large file will not load into memory despite Task Manager saying that you have 2GB of free memory. It is not uncommon to find a forum posting somewhere from someone that has a large image file (a satellite phote, MRI scan, etc) that is about 1GB in size. They wish to load it into memory, do in-memory processing on it, save the results, discard the memory then repeat the process, often for numerous images.
Typically on the third attempt to load a large file, the file will not load and the forum poster is left very confused.

The typical implementation is to allocate space for the large file using a call such as malloc() or operator new(). Both of which use the C runtime heap to allocate the memory.

The principle seems fine, but the problem is caused by memory fragmentation which results in a less accessible, totally usable, free space because the remaining free space blocks are separated into a many smaller regions, most of which are smaller than any forthcoming large allocation required by the application. Without the information about where pages and paragraphs are situated, how big they are and what their status is, identifying the cause of this failure could be very time consuming. Once you know the cause, you can think about allocating and managing your memory differently and prevent the bug from happening in the first place.

For situations like these, using HeapAlloc() with a dedicate heap (created using HeapCreate()) or even just directly using VirtualAlloc() will most likely lead to superior results than using the C runtime heap.

Tools
A first step in understanding such bugs is to be able to visualize the memory and to also inspect the various page and paragraph information.

To aid in these tasks we have just added a VM Pages view and VM Paragraphs view to VM Validator to make identifying such issues easier. VM Validator is a free download.

Memory Validator will also be updated with a VM Paragraphs view in the next release (Memory Validator already has a more detailed VM Pages view).

Thank you to Blake Miller of Invensys for suggesting an alternative wording for one paragraph of this article.

Share

Panorama Theme by Themocracy