请问:当线程被强行结束时如何释放堆上new的内存?

时间:2021-12-04 20:41:42
通过dll的一个导出函数中创建了线程,在该线程的InitInstance初始化部分通过new分配了大量的C++对象以及Windows资源窗口等等。如果该函数正常调用,并且线程正常结束时在ExitInstance中通过delete以及DestroyWindow等等释放资源。
如果该函数已经被调用,可是线程还在执行中时,当用户非正常结束主程序,线程将被强行结束,主程序将终止,Dll最终会被释放。此时无法进入线程的ExitInstance中来释放资源,在VC的Debug窗口中提示内存泄露。由于该函数可以被多次调用,可能产生多个线程,多次调用将进一步加大了内存泄漏。
由于使用的是regular dll,无论如何在Dll被释放时会调用CWinApp::ExitInstance,我计划通过每次在函数中创建线程时,将所创建的对象以及窗口资源的句柄通过vector保存在theApp的内部,当线程正常结束时修改theApp的vector[i]为NULL,当整个Dll卸载时,判断相应的值,如果不为NULL就执行释放工作。在往vector注册时我通过CCriticalSection保证一致。
可是发现,在异常退出清理资源时,无法成功delete掉new出的东西,而且DestroyWindow也不能奏效,引发了ASSERT失败。通过检测发现:在调用CWinApp::ExitInstance之前,所有创建的线程均已经终止。
请问:
以上情况下,为什么无法delete掉堆上new出的东西?是通过同一个指针值访问的。窗口句柄也无效。
有没有办法监控线程,在异常终止之前能够保证释放资源。
谢谢

9 个解决方案

#1


MFC规则DLL中的CWinApp对象是一个全局变量,在卸载DLL的时候调用ExitInstance,不是每个线程结束都调用的。
线程中可以用try来捕获异常,释放资源。

#2


如果线程被强行终止,调用堆栈中所有函数中new的堆内存(对象)都没有机会释放了。

如果有可能还是要让线程通过event得到事件,自己终止

#3


引用 2 楼 phisherr 的回复:
如果线程被强行终止,调用堆栈中所有函数中new的堆内存(对象)都没有机会释放了。

如果有可能还是要让线程通过event得到事件,自己终止

或者主线程里最后return之前加一句WaitForSingleOjbect(hChildThread, INFINITE); 等待子线程结束后再退出。

#4


不同模块(dll,exe)分配内存可能在不同的heap上做的,这样你在exe中 delete在dll中分配的内存,delete还是试图在exe的堆上查找这个要被删除的内存,因此要失败

如果线程被TerminateThread结束,他是没有任何机会去释放东西的。因此好的多线程程序要尽量避免使用TerminateThread。所有的在线程内的操作都应该找一种可中止的方法,因此你可以通知线程自己结束自己,这样才安全。
引用楼主 fangxu1999 的帖子:
通过dll的一个导出函数中创建了线程,在该线程的InitInstance初始化部分通过new分配了大量的C++对象以及Windows资源窗口等等。如果该函数正常调用,并且线程正常结束时在ExitInstance中通过delete以及DestroyWindow等等释放资源。 
如果该函数已经被调用,可是线程还在执行中时,当用户非正常结束主程序,线程将被强行结束,主程序将终止,Dll最终会被释放。此时无法进入线程的ExitInstance中来释放资源,在VC的Debug窗口中提示…

#5


引用 1 楼 cnzdgs 的回复:
MFC规则DLL中的CWinApp对象是一个全局变量,在卸载DLL的时候调用ExitInstance,不是每个线程结束都调用的。 
线程中可以用try来捕获异常,释放资源。

ExitInstance是整个进程结束,卸载dll时调用,所以我将线程所申请的资源记录了下来,以备在异常退出时有机会delete。然而在异常退出时,这个delete操作却无法得以实现,引发了断言失败。不知该如何处理了。
对于线程中用try来捕获异常,我看主要是线程执行过程内部出现的异常情况,当外部用户强行结束进程,进而终止了线程的运行是无法捕获的吧。
我的线程是一个GUI线程,主要用来显示其他后台线程的执行状况信息的,该GUI线程中申请了许多资源,如果按照正常的执行逻辑能够完成任务,不会抛出异常信息的,也就不能try任何东西了啊。
还请指教。

#6


可以考虑HOOK强行终止应用程序的API(如TerminateProcess)的方法来避免此事。

应该程序拦截到这个调用以后,就自己优雅终止所有线程的执行,然后退出运行。

#7


引用 4 楼 arong1234 的回复:
不同模块(dll,exe)分配内存可能在不同的heap上做的,这样你在exe中 delete在dll中分配的内存,delete还是试图在exe的堆上查找这个要被删除的内存,因此要失败 

这一点我可能没有讲清楚。我的exe仅仅是调用了该Dll的一个导出函数doSomething(),所有的功能实现、资源分配释放工作均交给dll来做了。所以应该算是在同一个模块上面分配的吧?而且我用了
AFX_MANAGE_STATE(AfxGetStaticModuleState());

据说是在模块之间切换,只是不晓得有什么作用罢了,能否说明一下啊。谢谢

引用 4 楼 arong1234 的回复:
如果线程被TerminateThread结束,他是没有任何机会去释放东西的。因此好的多线程程序要尽量避免使用TerminateThread。所有的在线程内的操作都应该找一种可中止的方法,因此你可以通知线程自己结束自己,这样才安全。 

这里仍然是同样的问题了,线程本身是“没有任何机会去释放东西的”,我们能不能在线程的外部,通过其他手段来释放这些东西呢?CWinApp::ExitInstance是肯定要执行的,所以我想在这里来释放东西,可是不成功。
请问问题出在哪里?或是有没有其他的时机来这些释放资源呢?

虽然说是外部用户不正常操作引起的,可是我看着Debug窗口中的那一堆泄漏报告,很不爽。我希望这个Dll是一个自包含的东西。有没有办法能够解决啊?谢谢了

#8


该回复于2008-07-20 19:37:06被版主删除

#9


我的理解是不会内存泄漏的,因为APP退出,一切都GAME over聊,APP申请的内存,一定会还给系统。(找个还是强制性的还)

#1


MFC规则DLL中的CWinApp对象是一个全局变量,在卸载DLL的时候调用ExitInstance,不是每个线程结束都调用的。
线程中可以用try来捕获异常,释放资源。

#2


如果线程被强行终止,调用堆栈中所有函数中new的堆内存(对象)都没有机会释放了。

如果有可能还是要让线程通过event得到事件,自己终止

#3


引用 2 楼 phisherr 的回复:
如果线程被强行终止,调用堆栈中所有函数中new的堆内存(对象)都没有机会释放了。

如果有可能还是要让线程通过event得到事件,自己终止

或者主线程里最后return之前加一句WaitForSingleOjbect(hChildThread, INFINITE); 等待子线程结束后再退出。

#4


不同模块(dll,exe)分配内存可能在不同的heap上做的,这样你在exe中 delete在dll中分配的内存,delete还是试图在exe的堆上查找这个要被删除的内存,因此要失败

如果线程被TerminateThread结束,他是没有任何机会去释放东西的。因此好的多线程程序要尽量避免使用TerminateThread。所有的在线程内的操作都应该找一种可中止的方法,因此你可以通知线程自己结束自己,这样才安全。
引用楼主 fangxu1999 的帖子:
通过dll的一个导出函数中创建了线程,在该线程的InitInstance初始化部分通过new分配了大量的C++对象以及Windows资源窗口等等。如果该函数正常调用,并且线程正常结束时在ExitInstance中通过delete以及DestroyWindow等等释放资源。 
如果该函数已经被调用,可是线程还在执行中时,当用户非正常结束主程序,线程将被强行结束,主程序将终止,Dll最终会被释放。此时无法进入线程的ExitInstance中来释放资源,在VC的Debug窗口中提示…

#5


引用 1 楼 cnzdgs 的回复:
MFC规则DLL中的CWinApp对象是一个全局变量,在卸载DLL的时候调用ExitInstance,不是每个线程结束都调用的。 
线程中可以用try来捕获异常,释放资源。

ExitInstance是整个进程结束,卸载dll时调用,所以我将线程所申请的资源记录了下来,以备在异常退出时有机会delete。然而在异常退出时,这个delete操作却无法得以实现,引发了断言失败。不知该如何处理了。
对于线程中用try来捕获异常,我看主要是线程执行过程内部出现的异常情况,当外部用户强行结束进程,进而终止了线程的运行是无法捕获的吧。
我的线程是一个GUI线程,主要用来显示其他后台线程的执行状况信息的,该GUI线程中申请了许多资源,如果按照正常的执行逻辑能够完成任务,不会抛出异常信息的,也就不能try任何东西了啊。
还请指教。

#6


可以考虑HOOK强行终止应用程序的API(如TerminateProcess)的方法来避免此事。

应该程序拦截到这个调用以后,就自己优雅终止所有线程的执行,然后退出运行。

#7


引用 4 楼 arong1234 的回复:
不同模块(dll,exe)分配内存可能在不同的heap上做的,这样你在exe中 delete在dll中分配的内存,delete还是试图在exe的堆上查找这个要被删除的内存,因此要失败 

这一点我可能没有讲清楚。我的exe仅仅是调用了该Dll的一个导出函数doSomething(),所有的功能实现、资源分配释放工作均交给dll来做了。所以应该算是在同一个模块上面分配的吧?而且我用了
AFX_MANAGE_STATE(AfxGetStaticModuleState());

据说是在模块之间切换,只是不晓得有什么作用罢了,能否说明一下啊。谢谢

引用 4 楼 arong1234 的回复:
如果线程被TerminateThread结束,他是没有任何机会去释放东西的。因此好的多线程程序要尽量避免使用TerminateThread。所有的在线程内的操作都应该找一种可中止的方法,因此你可以通知线程自己结束自己,这样才安全。 

这里仍然是同样的问题了,线程本身是“没有任何机会去释放东西的”,我们能不能在线程的外部,通过其他手段来释放这些东西呢?CWinApp::ExitInstance是肯定要执行的,所以我想在这里来释放东西,可是不成功。
请问问题出在哪里?或是有没有其他的时机来这些释放资源呢?

虽然说是外部用户不正常操作引起的,可是我看着Debug窗口中的那一堆泄漏报告,很不爽。我希望这个Dll是一个自包含的东西。有没有办法能够解决啊?谢谢了

#8


该回复于2008-07-20 19:37:06被版主删除

#9


我的理解是不会内存泄漏的,因为APP退出,一切都GAME over聊,APP申请的内存,一定会还给系统。(找个还是强制性的还)