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

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

To SSD or not SSD? That is the question

By , September 14, 2011 11:56 am

SSDs, or Solid State Disks are fast becoming the thing to have.

With no moving parts they should, in theory, be more reliable than the spinning disks most of us use now. They should also use less power and be faster as well. And in many cases this is the case. But not always. With SSDs you have to be aware of wear levelling – the memory can only be written to a finite number of times before it wears out. Also SSDs are in their infancy compared to the lifetime of the spinning disk industry. As such the reliability issues are not completely resolved.

Operating System

I’ve been interested in SSDs for a while. My first hurdle was that I wanted to use SSDs with Windows XP, but XP doesn’t know about SSDs and thus could potentially wear an SSD out quite quickly with its paging mechanism. Vista and Windows 7 know about SSDs and treat them differently to normal spinning disks so this is not a problem.

SSD user experience

When I went to MicroConf (see the many posts on this blog about that event) I met quite a few owners of MacBook Air computers. These all ship with SSDs. All of them said the same thing – the SSD is the single biggest win for them. To quote one them (sorry, I didn’t get his name) “I had a MacBook with a faster processor but this MacBook Air with a slower processor is a faster computer”. The difference was the SSD. That is quite a statement coming from a developer. He had downgraded his processor but the net result was a better, faster experience due to the SSD.

Talking with other delegates during the conference it was clear that there was quite a bit of interest in SSDs. A bit of research shows that in most circumstances SSD reads will outperform spinning disks greatly and SSD writes will outperform spinning disks greatly. But there are a few circumstances where SSD writes can be very slow and get outperformed by spinning disks. So depending on your usage, SSDs may not be for you. My guess is that for laptop/desktop users SSDs are going to a big win, but server farms with databases writing lots of data may be a problem.

Problems

Despite the wonderful comments from the MacBook Air users I was still concerned about reliability and wear levelling. After some research it turns out that you are more likely to replace your entire computer before wear levelling becomes a serious issue than you are to actually hit wear levelling problems.

That just leaves reliability. This is a problem. When spinning disks die, the controller or an actuator or some other circuitry often dies, leaving the disk completely intact or with minor damage. You can take this to a specialist, pay them some cash and they’ll pull all your data off the broken disk and put it on a new one. Inconvenient, but a result.

With SSDs the notion of cylinder, sectors etc typical of spinning disks goes away. Due to compatibility with SATA and the drop in replacement nature of SSDs these concepts may be used to address the data even though they no longer actually represent a physical location on the disk. The SSD controller maps these values to a virtual location in the SSD memory. That location may change over time to improve the SSD’s performance or to handle wear levelling. With SSDs the controller is typically the failure point and given that the data is spread all over the disk to handle wear levelling and whatever other concerns the controller has you can’t easily identify which SSD locations constitute a file, making it very hard or even impossible to pull data off a dead SSD.

A few weeks ago my father called me to ask if I could help his neighbour with an SSD problem. I could not help. His SSD had died and he had no way to pull many years of family photos from the SSD. And he hadn’t made a backup! Ouch! He’d replaced his spinning disk with an SSD three months earlier. Was really pleased with the performance until one day it just did not work. I’ve found similar tales on the net of server farms taking delivery of cases of SSDs and finding up to 50% dead on arrival!

So with that I’m going to postpone switching to SSDs. I sure could use the speed boost, but just one lost day restoring my data is not worth the effort.

So what else is there?

Turns out there is a solution which has much of the SSD benefits and retains the ability to easily pull data of a dead drive. That solution is the Hybrid SSD. I’ve replaced the spinning disk on this computer with a Hybrid SSD from Seagate. It has a 4GB SSD style data area to read from for all frequently requested data (it learns what apps you use and stores them in the SSD area) but all writes go straight to disk, not into the SSD area. The result is that writes happen at typical spinning disk speeds and reads for random data also happen at typical spinning disk speeds. But programs you frequently run are typically in the 4GB area and start very much quicker.

Also, because it isn’t an SSD you can just use it as a drop in replacement for any SATA drive on any OS – the OS can treat it just like an spinning disk and not be concerned about wear levelling. So you can use it with Windows XP quite happily.

I’ve simplified how it operates greatly, but the end result if I’ve got a snappy feeling machine just by changing my drive to a Hybrid SSD.

Share

Panorama Theme by Themocracy