线程关闭,出现大量内存泄露,如何处理?

时间:2022-06-29 22:47:52
当主线程创建一个辅助线程的时候,如果当我关闭应用程序(关闭主线程),主线程会关闭辅助线程,但是若辅助线程里有个函数执行时间相当长,当然主线程也会灭掉辅助线程,但是会导致内存泄露!当我按F5调试运行,会看到很多的内存泄露,该怎么办啊?

21 个解决方案

#1


不太明白lz的意思~


主线程结束,整个进程都结束了~什么资源都释放了~

#2


你一定是强行终止了线程!

#3


强行终止系统不会知道有泄露的,肯定还是你程序的问题,根据泄露的提示信息一般猜出一些端倪

#4


只要线程终止,主程序也就终止了,系统会回收资源啊!

#5


是调用了TERMINATE来终止的吧
这不行的,会导致泄露
应该用一个volatile变量来指示线程什么时间退出
如果是消息驱动的,那么应该在耗费时间的函数中检测这个volatile,防止无限制等待
反正一定要让线程自己返回,否则无法知道会发生什么问题

#6


skt01(skt001)和niying(逆颖)的说法是不正确的。
vc中显示内存泄漏是调试器机制,可以注意到打印信息是在.exe中止之前出现的,调试器自然知道你有哪些内存没释放(通过重载new 和delete实现)。
那么自然,如果子线程中用过new,这时候主线程需要退出,先杀死子线程(系统使用了Terminate),那么内存肯定泄漏了。
关键是程序实现方法有问题,主线程应该等待子线程完成工作(waitfor...),然后再退出。其实内存还好说,退出也就退出了,但如果是其他,比如文件,就可能有意想不到的结果。所以需要等待子线程完成工作,当然如果是调试时强制中止主线程,内存泄漏当然无法避免。

#7


关键是程序实现方法有问题,主线程应该等待子线程完成工作(waitfor...),然后再退出。其实内存还好说,退出也就退出了,但如果是其他,比如文件,就可能有意想不到的结果。所以需要等待子线程完成工作,当然如果是调试时强制中止主线程,内存泄漏当然无法避免。
=============================
同意这种说法~呵呵

#8


主线程结束那么程序也就结束了,操作系统会帮你把所有的资源都回收的,即使是强行退出。但是如果主线程没有结束,只是他创建的子线程结束了,那么就会造成内存泄漏,内存泄漏是因为在堆上动态创建了内存,所以检查一下你的new或者malloc的应用,是否有对应的释放就可以查处来了。

#9


各位大哥,先什么都不要管,我做了个测试才发帖子问这个问题的:我建立了一个基于对话框应用程序,放了一个按钮,当点击这个按钮时,启动一个新的线程:AfxBeginThread();而这个线程我没有用new、malloc等在堆上分配内存,为了测试,我就while(1) ;(虽然在现实中不可能这样做,但也没有什么恶果,呵呵..)。那么这个线程就不会返回了。这个时候我调试运行,点击按钮启动线程,接着关闭应用程序(即关闭主线程),我没有在程序的任何地方加TerminateThread()或AfxEndThread(),即没有作任何处理,程序能够正常退出,没有警告,没有报错,但是出现了内存泄露,几条内存泄露信息,有一条还有100多字节。请问大家怎么解释?

#10


嗯,我可以证实确实是这样的。
output出来这一坨:
Detected memory leaks!
Dumping objects ->
thrdcore.cpp(166) : {75} client block at 0x00C026A0, subtype 0, 108 bytes long.
a CWinThread object at $00C026A0, 108 bytes long
Object dump complete.
The thread 0xC50 has exited with code 0 (0x0).

跟到代码里看,原来是这样:
CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam,
int nPriority, UINT nStackSize, DWORD dwCreateFlags,
LPSECURITY_ATTRIBUTES lpSecurityAttrs)
{
#ifndef _MT
pfnThreadProc;
pParam;
nPriority;
nStackSize;
dwCreateFlags;
lpSecurityAttrs;

return NULL;
#else
ASSERT(pfnThreadProc != NULL);

CWinThread* pThread = DEBUG_NEW CWinThread(pfnThreadProc, pParam);// 166行
ASSERT_VALID(pThread);

if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,
lpSecurityAttrs))
{
pThread->Delete();
return NULL;
}
VERIFY(pThread->SetThreadPriority(nPriority));
if (!(dwCreateFlags & CREATE_SUSPENDED))
VERIFY(pThread->ResumeThread() != (DWORD)-1);

return pThread;
#endif //!_MT)
}

原来是DEBUG_NEW的pThread没有释放,赫赫。
看来线程还是应该安全退出的,这个泄露确实只有lz那样的细心人才会发现。

#11


用waitfor...当然是最好不过了。

Lz的Ls说的问题,如果不想用waitfor...,可以这样,AfxBeginThread()有个返回值,好像是CWinThread*类型,赋给某个变量m_pThread记录下来,对话框析构的时候,先TerminateThread()外部结束,然后delete m_pThread就不会有内存泄漏了。不过最好把TerminateThread和delete放在try{}catch(...){}里面,这样即便是那个线程结束也不会出错……

#12


Lz的Ls?赫赫,不会是老师吧。
嗯,楼上说的也有道理。不过最好还是wait,我认为。

#13


terminatethread始终是在迫不得已的情况下才调用的,terminatethread后,被terminate的线程的heap和stack都不会自动释放,同样,线程所申请的操作系统资源也得不到释放,最危险还是像criticalsection、event之类的东西,进入后不能自动退出,这可是会导致死锁的,所以terminatethread请三思而后行。

#14



还是设定事件对象来跟主线程进行通信,然后用waitfor...让辅助线程确定是否退出。
当主线程退出时要释放 m_pThread所指的线程对象,执行delete  m_pThread;之前让主线程检测一下辅助线程是退出,当正常退出后再delete  m_pThread;
不要强行用一个线程去终止别的线程,线程终止的最好方式是函数的正常退出,即执行return

#15


w_anthony()的这种作法我已经做过了,但还是有内存的泄露,不信试试看!

#16


dadi0189(流年似水......)所说确实有道理!~但你不的不承认一个事实:有的线程干的活比较多,你说通过事件的方式让辅助线程马上完成,立即return,举个例子:辅助线程调用一个控件里的函数,这个函数执行5秒钟才返回,它后面的一条语句才是等待主线程设置的事件对象(WaitForSingleEvent()),你总不可能在这个控件里的那个函数里加WaitForSingleEvent()吧?而在这个时候你关闭了应用程序(即关闭主线程),那么主线程会杀死辅助线程,造成资源的泄露!即使你在这个主线程的析构函数里激活辅助线程的WaitForSingleEvent()等待的事件,但已经说了,辅助线程里的一个函数还没有执行,那WaitForSingleEvent()能等到这个事件吗?所以这个时候还是主线程强行关闭辅助现成,造成资源泄露!!至于用TerminateThread(),那当然
是In Vain,因为辅助线程没有执行完,这样还是强行终止啊!这个问题?

#17


w_anthony()的这种作法我已经做过了,但还是有内存的泄露,不信试试看!?

拜托,我记得以前这样是不会有内存泄露的。今天听你说了,我特地又去试了一下,还是没有内存泄露。你怎么写的?要不要我发一份代码给你?

#18


dadi0189(流年似水......)所说确实有道理!~但你不的不承认一个事实:有的线程干的活比较多,你说通过事件的方式让辅助线程马上完成,立即return,举个例子:辅助线程调用一个控件里的函数,这个函数执行5秒钟才返回,它后面的一条语句才是等待主线程设置的事件对象(WaitForSingleEvent()),你总不可能在这个控件里的那个函数里加WaitForSingleEvent()吧?而在这个时候你关闭了应用程序(即关闭主线程),那么主线程会杀死辅助线程,造成资源的泄露!即使你在这个主线程的析构函数里激活辅助线程的WaitForSingleEvent()等待的事件,但已经说了,辅助线程里的一个函数还没有执行,那WaitForSingleEvent()能等到这个事件吗?所以这个时候还是主线程强行关闭辅助现成,造成资源泄露!!至于用TerminateThread(),那当然
是In Vain,因为辅助线程没有执行完,这样还是强行终止啊!这个问题?
=====================================
老兄,你说得有道理,但你主线程将要退出时应该检测一下辅助线程是否已正常退出了,要隔一小段时间反复检测直至线程已退出。辅助线程里如果调用了阻塞函数,就为把阻塞函数设置一个超时值,一般阻塞调用都提供这个参数,这样函数就在规定的时间里返回了,主线程检测到了就退出。

#19


这个问题很好解决
设置一个主线程和辅助线程都可以看得见得BOOL变量,主线程退出事件发生时将这个BOOL变量置为TRUE,而辅助线程里面执行一点就检查一下这个值是否为TRUE,TRUE的时候就不要做后面的事情了,然后退出。主线程一直等待到子线程退出后再退出。

我每次都是这样做的,没有出现过内存泄露等问题。

#20


但你主线程将要退出时应该检测一下辅助线程是否已正常退出了,要隔一小段时间反复检测直至线程已退出。辅助线程里如果调用了阻塞函数,就为把阻塞函数设置一个超时值,一般阻塞调用都提供这个参数,这样函数就在规定的时间里返回了,主线程检测到了就退出。
=====================================================================================
老兄,就是因为调用了阻塞函数,而且是人家已经写好的控件里的成员函数,就是这个问题吗?这个函数没有结束(要10秒钟才返回),辅助线程当然就没有退出?要是等到规定的10秒才结束辅助线程,怎么可能呢?主线程关闭了,也就杀死了辅助线程,哪还等10秒啊?就是因为这个线程是主线程强行杀死的,所以才造成泄露啊,老兄.

#21


已经发过去了,csdn的短消息提示实在太烂……

#1


不太明白lz的意思~


主线程结束,整个进程都结束了~什么资源都释放了~

#2


你一定是强行终止了线程!

#3


强行终止系统不会知道有泄露的,肯定还是你程序的问题,根据泄露的提示信息一般猜出一些端倪

#4


只要线程终止,主程序也就终止了,系统会回收资源啊!

#5


是调用了TERMINATE来终止的吧
这不行的,会导致泄露
应该用一个volatile变量来指示线程什么时间退出
如果是消息驱动的,那么应该在耗费时间的函数中检测这个volatile,防止无限制等待
反正一定要让线程自己返回,否则无法知道会发生什么问题

#6


skt01(skt001)和niying(逆颖)的说法是不正确的。
vc中显示内存泄漏是调试器机制,可以注意到打印信息是在.exe中止之前出现的,调试器自然知道你有哪些内存没释放(通过重载new 和delete实现)。
那么自然,如果子线程中用过new,这时候主线程需要退出,先杀死子线程(系统使用了Terminate),那么内存肯定泄漏了。
关键是程序实现方法有问题,主线程应该等待子线程完成工作(waitfor...),然后再退出。其实内存还好说,退出也就退出了,但如果是其他,比如文件,就可能有意想不到的结果。所以需要等待子线程完成工作,当然如果是调试时强制中止主线程,内存泄漏当然无法避免。

#7


关键是程序实现方法有问题,主线程应该等待子线程完成工作(waitfor...),然后再退出。其实内存还好说,退出也就退出了,但如果是其他,比如文件,就可能有意想不到的结果。所以需要等待子线程完成工作,当然如果是调试时强制中止主线程,内存泄漏当然无法避免。
=============================
同意这种说法~呵呵

#8


主线程结束那么程序也就结束了,操作系统会帮你把所有的资源都回收的,即使是强行退出。但是如果主线程没有结束,只是他创建的子线程结束了,那么就会造成内存泄漏,内存泄漏是因为在堆上动态创建了内存,所以检查一下你的new或者malloc的应用,是否有对应的释放就可以查处来了。

#9


各位大哥,先什么都不要管,我做了个测试才发帖子问这个问题的:我建立了一个基于对话框应用程序,放了一个按钮,当点击这个按钮时,启动一个新的线程:AfxBeginThread();而这个线程我没有用new、malloc等在堆上分配内存,为了测试,我就while(1) ;(虽然在现实中不可能这样做,但也没有什么恶果,呵呵..)。那么这个线程就不会返回了。这个时候我调试运行,点击按钮启动线程,接着关闭应用程序(即关闭主线程),我没有在程序的任何地方加TerminateThread()或AfxEndThread(),即没有作任何处理,程序能够正常退出,没有警告,没有报错,但是出现了内存泄露,几条内存泄露信息,有一条还有100多字节。请问大家怎么解释?

#10


嗯,我可以证实确实是这样的。
output出来这一坨:
Detected memory leaks!
Dumping objects ->
thrdcore.cpp(166) : {75} client block at 0x00C026A0, subtype 0, 108 bytes long.
a CWinThread object at $00C026A0, 108 bytes long
Object dump complete.
The thread 0xC50 has exited with code 0 (0x0).

跟到代码里看,原来是这样:
CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam,
int nPriority, UINT nStackSize, DWORD dwCreateFlags,
LPSECURITY_ATTRIBUTES lpSecurityAttrs)
{
#ifndef _MT
pfnThreadProc;
pParam;
nPriority;
nStackSize;
dwCreateFlags;
lpSecurityAttrs;

return NULL;
#else
ASSERT(pfnThreadProc != NULL);

CWinThread* pThread = DEBUG_NEW CWinThread(pfnThreadProc, pParam);// 166行
ASSERT_VALID(pThread);

if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,
lpSecurityAttrs))
{
pThread->Delete();
return NULL;
}
VERIFY(pThread->SetThreadPriority(nPriority));
if (!(dwCreateFlags & CREATE_SUSPENDED))
VERIFY(pThread->ResumeThread() != (DWORD)-1);

return pThread;
#endif //!_MT)
}

原来是DEBUG_NEW的pThread没有释放,赫赫。
看来线程还是应该安全退出的,这个泄露确实只有lz那样的细心人才会发现。

#11


用waitfor...当然是最好不过了。

Lz的Ls说的问题,如果不想用waitfor...,可以这样,AfxBeginThread()有个返回值,好像是CWinThread*类型,赋给某个变量m_pThread记录下来,对话框析构的时候,先TerminateThread()外部结束,然后delete m_pThread就不会有内存泄漏了。不过最好把TerminateThread和delete放在try{}catch(...){}里面,这样即便是那个线程结束也不会出错……

#12


Lz的Ls?赫赫,不会是老师吧。
嗯,楼上说的也有道理。不过最好还是wait,我认为。

#13


terminatethread始终是在迫不得已的情况下才调用的,terminatethread后,被terminate的线程的heap和stack都不会自动释放,同样,线程所申请的操作系统资源也得不到释放,最危险还是像criticalsection、event之类的东西,进入后不能自动退出,这可是会导致死锁的,所以terminatethread请三思而后行。

#14



还是设定事件对象来跟主线程进行通信,然后用waitfor...让辅助线程确定是否退出。
当主线程退出时要释放 m_pThread所指的线程对象,执行delete  m_pThread;之前让主线程检测一下辅助线程是退出,当正常退出后再delete  m_pThread;
不要强行用一个线程去终止别的线程,线程终止的最好方式是函数的正常退出,即执行return

#15


w_anthony()的这种作法我已经做过了,但还是有内存的泄露,不信试试看!

#16


dadi0189(流年似水......)所说确实有道理!~但你不的不承认一个事实:有的线程干的活比较多,你说通过事件的方式让辅助线程马上完成,立即return,举个例子:辅助线程调用一个控件里的函数,这个函数执行5秒钟才返回,它后面的一条语句才是等待主线程设置的事件对象(WaitForSingleEvent()),你总不可能在这个控件里的那个函数里加WaitForSingleEvent()吧?而在这个时候你关闭了应用程序(即关闭主线程),那么主线程会杀死辅助线程,造成资源的泄露!即使你在这个主线程的析构函数里激活辅助线程的WaitForSingleEvent()等待的事件,但已经说了,辅助线程里的一个函数还没有执行,那WaitForSingleEvent()能等到这个事件吗?所以这个时候还是主线程强行关闭辅助现成,造成资源泄露!!至于用TerminateThread(),那当然
是In Vain,因为辅助线程没有执行完,这样还是强行终止啊!这个问题?

#17


w_anthony()的这种作法我已经做过了,但还是有内存的泄露,不信试试看!?

拜托,我记得以前这样是不会有内存泄露的。今天听你说了,我特地又去试了一下,还是没有内存泄露。你怎么写的?要不要我发一份代码给你?

#18


dadi0189(流年似水......)所说确实有道理!~但你不的不承认一个事实:有的线程干的活比较多,你说通过事件的方式让辅助线程马上完成,立即return,举个例子:辅助线程调用一个控件里的函数,这个函数执行5秒钟才返回,它后面的一条语句才是等待主线程设置的事件对象(WaitForSingleEvent()),你总不可能在这个控件里的那个函数里加WaitForSingleEvent()吧?而在这个时候你关闭了应用程序(即关闭主线程),那么主线程会杀死辅助线程,造成资源的泄露!即使你在这个主线程的析构函数里激活辅助线程的WaitForSingleEvent()等待的事件,但已经说了,辅助线程里的一个函数还没有执行,那WaitForSingleEvent()能等到这个事件吗?所以这个时候还是主线程强行关闭辅助现成,造成资源泄露!!至于用TerminateThread(),那当然
是In Vain,因为辅助线程没有执行完,这样还是强行终止啊!这个问题?
=====================================
老兄,你说得有道理,但你主线程将要退出时应该检测一下辅助线程是否已正常退出了,要隔一小段时间反复检测直至线程已退出。辅助线程里如果调用了阻塞函数,就为把阻塞函数设置一个超时值,一般阻塞调用都提供这个参数,这样函数就在规定的时间里返回了,主线程检测到了就退出。

#19


这个问题很好解决
设置一个主线程和辅助线程都可以看得见得BOOL变量,主线程退出事件发生时将这个BOOL变量置为TRUE,而辅助线程里面执行一点就检查一下这个值是否为TRUE,TRUE的时候就不要做后面的事情了,然后退出。主线程一直等待到子线程退出后再退出。

我每次都是这样做的,没有出现过内存泄露等问题。

#20


但你主线程将要退出时应该检测一下辅助线程是否已正常退出了,要隔一小段时间反复检测直至线程已退出。辅助线程里如果调用了阻塞函数,就为把阻塞函数设置一个超时值,一般阻塞调用都提供这个参数,这样函数就在规定的时间里返回了,主线程检测到了就退出。
=====================================================================================
老兄,就是因为调用了阻塞函数,而且是人家已经写好的控件里的成员函数,就是这个问题吗?这个函数没有结束(要10秒钟才返回),辅助线程当然就没有退出?要是等到规定的10秒才结束辅助线程,怎么可能呢?主线程关闭了,也就杀死了辅助线程,哪还等10秒啊?就是因为这个线程是主线程强行杀死的,所以才造成泄露啊,老兄.

#21


已经发过去了,csdn的短消息提示实在太烂……