Click here to Skip to main content
15,903,201 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am having a memory leak problem using stl::vector in visual c++. I store a very large amount of data in a vector in a thread. If I exit the thread (where the vector object is) and quickly exit the program, I get a memory leak. If I exit the thread but wait 10 seconds before exiting the program, I get no memory leak. I am guessing that by waiting, I give the vector destructor enough time to deallocate memory for all of it's elements. Does this make sense? I can think of no other explanantion for what I am seeing. And if this is what is actually happening, how can I tell when the vector destructor has finished freeing memory so I can wait to exit the program until it's finished? Or should I not worry about a memory leak in this case? Thanks in advance.
Posted
Updated 3-Dec-10 6:48am
v2

Depends a lot on what you mean by exiting a thread. If you just kill the thread by another thread using TerminateThread() is generally bad. If you call ExitThread() from your thread that can also be a problem. if you use the winapi CreateThread() then your ThreadProc has a return value and its much nicer just to return from your function. If you are using _beginthread() and _endthread() then its much better to do nothing in your threadproc but calling another function that has a return value and calling _endthread() with that return value. This way the called function can return normally and its stack objects (eg.: your vectors) are destroyed, and you still can specify an exit code. If you terminate the thread from another thread, then its much better to signal first to the worker thread (for example by setting a volatile bool variable, or by setting an event). After this wait for some time using the handle of the thread and WaitForSingleObject(), and if the worker thread does not exit and WaitForSingleObject() timeouts then just kill the thread with TerminateThread(). If you are working with _beginthread() then you don't have a handle to wait for. In this case you should define an event and wait for that in the main thread. The worker thread should set this event just before exiting/returning after everything is cleant up.
 
Share this answer
 
Comments
JF2015 3-Dec-10 14:09pm    
Moved from fake Answer:

I use a dialog to capture the user exit from the thread. In pseudocode, I do in the main app:

mMyDialog.m_bCancel = FALSE;

AfxBeginThread(threadfunc, (LPVOID)this);

then with
UINT CMainApp::threadfunc(LPVOID pParam)
{
CMainApp * pApp = (CMainApp*)pParam;

while (!pApp->mMyDialog.m_bCancel)
pApp->func();

return 0;
}

and

CMainApp::func()
{
vector < something > data;

while (!mMyDialog.m_bCancel)
fill the vector and do stuff
}

When the user clicks the exit button in mMyDialog, m_bCancel is set to TRUE, func() exits, then threadfunc() exits, and the thread is done. I don't call AfxEndThread(), just return 0 from the controlling function. I think I'm already doing basically what you suggest with _beginthread() and _endthread().
Then you have to use an event as I described in the last few sentences. If you are not familiar with that then this description will help a lot, otherwise just ignore it. :)
Put an event object somewhere in your app class as a member HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);


Exactly after mMyDialog.m_bCancel = TRUE; when you press the cancel button wait for this event to become signaled:
WaitForSingleObject(hEvent, INFINITE);

You can replace INFINITE to some timeout if your worker thread is not safe and may hang forever. In this case it is good practice to call TerminateThread() after the timeout, but don't do this timeout/terminate thing if your worker thread 100% stops working when you set the cancel flag. In your worker thread after releasing your resources you should signal the event to tell the main thread so that it can continue execution (maybe do the program exit):
SetEvent(hEvent);
Don't put this into your func(), because the vector is on the stack and the function has to return in order to release the vector. If you singal the event inside func() then the main thread may terminate the prog before func() can cleanup gracefully. Instead put the event signaling after the call of func() when it is 100% sure that there are no releasable resources left, all what we have to do is exiting the thread:
while (!pApp->mMyDialog.m_bCancel)
  pApp->func();
SetEvent(hEvent);
// returning from thread or ExitThread() or whatever...

Don't forget to delete the event handle in the destructor of your class with CloseHandle(). If you want to use this event more than once for more operations then at the beginning of the operation don't forget to reset it with ResetEvent().

One more thing, because it doesn't take much time copy-pasting, Its always a good practice to encapsulate an API handle and the related API functions into a class/struct like the following: (you can use this wherever you would otherwise use a HANDLE that must be closed with CloseHandle() (for example your event object), and this often saves you from leaking a handle. Have fun!!! :)
// works like std::auto_ptr, operator= transfers the ownership
struct SWinHandle
{
	SWinHandle(HANDLE _handle=NULL)
		: handle(_handle)
	{
	}
	SWinHandle(SWinHandle& other)
		: handle(other)
	{
		other.handle = NULL;
	}
	~SWinHandle()
	{
		Close();
	}
	void Close()
	{
		if (handle!=NULL && handle!=INVALID_HANDLE_VALUE)
		{
			::CloseHandle(handle);
			handle = NULL;
		}
	}
	operator HANDLE() const
	{
		return handle;
	}
	HANDLE Release()
	{
		HANDLE h = handle;
		handle = NULL;
		return h;
	}
	SWinHandle& operator=(HANDLE _handle)
	{
		Close();
		handle = _handle;
		return *this;
	}
	SWinHandle& operator=(SWinHandle& other)
	{
		Close();
		handle = other;
		other.handle = NULL;
		return *this;
	}

	HANDLE handle;
};
 
Share this answer
 
Thanks!!! BTW, the vector of "something" above is a struct with a member that is also a vector (of ints). I changed that member from a vector to a fixed length array of ints, the memory leak went away. But I will try your suggestions since the member array length may change in some cases.
 
Share this answer
 
Try to implement the vector version as well! Knowing how to manage a few threads today is a MUST! :) And you won't always be that lucky to have only primitive non-dynamically allocated resources. :thumbsup:
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900