stl :: vector内存泄漏 [英] stl::vector memory leak

查看:69
本文介绍了stl :: vector内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Visual C ++中使用stl :: vector遇到内存泄漏问题.我在线程的向量中存储了大量数据.如果退出线程(矢量对象所在的位置)并快速退出程序,则会发生内存泄漏.如果我退出线程,但是在退出程序之前等待10秒钟,则不会出现内存泄漏.我猜想,通过等待,我给向量析构函数足够的时间为其所有元素释放内存.这有意义吗?我所看到的没有其他解释.如果这是实际发生的情况,如何确定向量析构函数何时完成释放内存,以便我可以等待退出程序直到完成?还是我不应该担心这种情况下的内存泄漏?在此先感谢.

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.

推荐答案

很大程度上取决于退出线程的含义.如果仅使用TerminateThread()杀死另一个线程,则通常是不好的.如果您从线程中调用ExitThread(),那也可能是一个问题.如果您使用winapi CreateThread(),则您的ThreadProc具有返回值,它的返回值要好得多,以便从函数中返回.如果您正在使用_beginthread()_endthread(),那么最好不要在threadproc中执行任何操作,而是调用另一个具有返回值的函数,并使用该返回值调用_endthread().这样,被调用函数可以正常返回,并且其堆栈对象(例如:向量)被销毁,并且您仍然可以指定退出代码.如果从另一个线程终止线程,则最好先向工作线程发出信号(例如,通过设置volatile bool变量或通过设置事件).此后,请使用线程和WaitForSingleObject()的句柄等待一段时间,如果工作线程未退出且WaitForSingleObject()超时,则只需使用TerminateThread()杀死该线程.如果使用_beginthread(),则没有等待的句柄.在这种情况下,您应该定义一个事件并在主线程中等待该事件.工作线程应该在清理完所有内容后退出/返回之前设置该事件.
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.


然后您必须使用我在最后几句话中描述的事件.如果您不熟悉此说明,那么此说明会很有帮助,否则请忽略它. :)
将事件对象作为成员HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
放置在您的应用程序类中的某个位置

恰好在mMyDialog.m_bCancel = TRUE;之后,当您按下取消"按钮时,等待该事件发出信号:
WaitForSingleObject(hEvent, INFINITE);

如果您的工作线程不安全并且可能永远挂起,则可以将INFINITE替换为某个超时.在这种情况下,最好在超时后调用TerminateThread(),但是如果您的工作线程在设置取消标志时100%停止工作,则不要执行此超时/终止操作.释放资源后,在工作线程中应通知事件以告知主线程以便其可以继续执行(也许可以退出程序):
SetEvent(hEvent);
不要将其放入您的func()中,因为向量在堆栈上,并且该函数必须返回才能释放向量.如果在func()内部标记事件,则在func()可以正常清理之前,主线程可能会终止该编.相反,当100%确保没有剩余的可释放资源时,将事件信令放在调用func()之后,我们要做的就是退出线程:
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...


不要忘记使用CloseHandle()删除类的析构函数中的事件句柄.如果要多次使用此事件进行更多操作,则在操作开始时不要忘记使用ResetEvent()重置它.

还有一件事,因为它不需要花费很多时间进行粘贴,因此将API句柄和相关的API函数封装到类/结构中始终是一个好习惯,如下所示:(您可以在其他任何地方使用它使用必须用CloseHandle()关闭的HANDLE(例如您的事件对象),这通常可以使您免于泄漏手柄.玩得开心!!! :)


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;
};


谢谢!!!顺便说一句,上面某物"的向量是一个结构,其成员也是(整数)向量.我将该成员从向量更改为固定长度的int数组,内存泄漏消失了.但我会尝试您的建议,因为在某些情况下成员数组的长度可能会发生变化.
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.


这篇关于stl :: vector内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆