MFC多线程内存泄漏问题&解决方法

在用visual studio进行界面编程时(如MFC),前台UI我们能够通过MFC的消息循环机制实现。而对于后台的数据处理。我们可能会用到多线程来处理。

那么对于大多数人(尤其是我这样的菜鸟),一个比較快捷的方法便是选择MFC多线程:AfxBeginThread或者CreateThread来进建立多线程。当一两个线程还是能够得。当有3个或者3个以上的线程出现时,极可能出现内存泄漏。原因分析例如以下:

CWinThread的多线程不安全性:

由于 CWinThread 会调用_beginthreadex来初始化C执行时库。而相同地,假设线程被强制终止(TerminateThread),由于  TerminateThread是不会去管 C执行时库的,从而,导致部分和引用计数相关的C执行时数据的内存释放出现故障。最典型的特征是,使用STL库的静态变量
内存回收将出错,从而导致进程退出时误报异常。

此外,假设AfxBeginThread频繁进行回收和分配线程,假设不严格操作,也会导致崩溃。

VC6中,应该严格控制STL库的使用,避免MFC库和STL库并存,否则,会有非常多问题。

原因:

AfxBeginThread在内部直接调用了CreateThread创建线程而不是c语言下推荐的beginthreadex函数,而这两个函数是有差别的,主要是c执行库的历史遗留问题造成的。

在多线程环境中存在问题的C/C++执行期库变量和函数包含errno、_doserrno、strtok、_wcstok、strerror、_strerror、tmpnam、tmpfile、asctime、_wasctime、gmtime、_ecvt和_fcvt等。

若要使多线程C/C++程序可以正确地执行,必须创建一个数据结构,并将它与使用C/C++执行期库函数的每一个线程关联起来。当你调用C / C + +执行期库时,这些函数必须知道查看调用线程的数据块,这样就不会对别的线程产生不良影响。

那么系统是否知道在创建新线程时分配该数据块呢?回答是它不知道。系统根本不知道你得到的应用程序是用C/C++编写的。也不知道你调用函数的线程本身是不安全的。问题在于你必须正确地进行全部的操作。

若要创建一个新线程。绝对不要调用操作系统的CreateThread函数。必须调用C/C++执行期库函数_beginthreadex。

以下是关于_beginthreadex的一些要点:

每一个线程均获得由C/C++执行期库的堆栈分配的自己的tiddata内存结构。(tiddata结构位于Mtdll.h文件里的Visual C++源码中)。传递给_beginthreadex的线程函数的地址保存在tiddata内存块中。

传递给该函数的參数也保存在该数据块中。

_beginthreadex确实从内部调用CreateThread,由于这是操作系统了解怎样创建新线程的唯一方法。###能够看出调用_beginthreadex时分配了额外的内存空间。

假设调用CreateThread,而不是调用C / C + +执行期库的_beginthreadex来创建新线程,将会发生什么情况。当一个线程调用要求tiddata结构的C / C + +执行期库函数时,将会发生以下的一些情况(大多数C / C + +执行期库函数都是线程安全函数,不须要该结构)。

先。 C / C + +执行期库函数试图(通过调用TlsGetValue)获取线程的数据块的地址。

假设返回

NULL作为tiddata块的地址。调用线程就不拥有与该地址相关的tiddata块。这时,C / C + +执行期库函数就在现场为调用线程分配一个tiddata块,并对它进行初始化。然后该tiddata块(通过TlsSetValue)与线程相关联。

###_beginthreadex相相应的推出函数是_endthreadex,这个函数会释放tiddata的内容。

---------------------------

假设你採用CreateThread创建线程。而你没有使用上面所提到的那些特殊执行期库的话,也是不会出现故障的。假设一定要用那些执行库的话就最好调用_beginthreadex 这个api来创建线程,否则tiddata数据块就无法撤销,引起内存泄漏。

你能够參照_beginthreadex源码来进行理解。

引申阅读:

关于_beginthreadex和CreateThread的差别

时间: 2024-10-20 07:42:25

MFC多线程内存泄漏问题&解决方法的相关文章

Java进程内存泄漏判断及解决方法

内存泄漏种类Java使用的内存种类包含三种,这三种类型的内存都可能发生内存泄漏.? 堆内存泄漏,如果JVM 不能在java 堆中获得更多内存来分配更多java 对象,将会抛出java堆内存不足(java OOM) 错误.如果java 堆充满了活动对象,并且JVM 无法再扩展java 堆,那么它将不能分配更多java 对象.更多情况是程序设计有问题,生成的对象占用过多的堆内存造成堆内存泄漏.? 本地内存泄漏, 如果JVM 无法获得更多本地内存,它将抛出本地OOM错误.当进程用到的内存到达操作系统的

MFC多线程内存泄漏问题&解决方法

在用visual studio进行界面编程时(如MFC),前台UI我们可以通过MFC的消息循环机制实现.而对于后台的数据处理,我们可能会用到多线程来处理.那么对于大多数人(尤其是我这种菜鸟),一个比较快捷的方法便是选择MFC多线程:AfxBeginThread或者CreateThread来进建立多线程.当一两个线程还是可以得,当有3个或者3个以上的线程出现时,极可能出现内存泄漏.原因分析如下: CWinThread的多线程不安全性: 因为 CWinThread 会调用_beginthreadex

使用HandyJSON导致的内存泄漏问题相关解决方法

在移动开发中,与服务器打交道是不可避免的,从服务器拿到的接口数据最终都会被我们解析成模型,现在比较常见的数据传输格式是json格式,对json格式的解析可以使用原生的解析方式,也可以使用第三方的,我们的项目中使用的是阿里开源的一个swift编写的解析框架--HandyJSON. 在使用过程中,使用instruments的Leak Checks工具对内存泄漏进行检测时发现了这个框架导致了不少的内存泄漏,如图1-1: 这张图是在APP进入首页并将数据加载完毕时截取的,可以看到,HandyJSON一共

Android开发 |常见的内存泄漏问题及解决办法

在Android开发中,内存泄漏是比较常见的问题,有过一些Android编程经历的童鞋应该都遇到过,但为什么会出现内存泄漏呢?内存泄漏又有什么影响呢? 在Android程序开发中,当一个对象已经不需要再使用了,本该被回收时,而另外一个正在使用的对象持有它的引用从而导致它不能被回收,这就导致本该被回收的对象不能被回收而停留在堆内存中,内存泄漏就产生了. 内存泄漏有什么影响呢?它是造成应用程序OOM的主要原因之一.由于Android系统为每个应用程序分配的内存有限,当一个应用中产生的内存泄漏比较多时

Android内存泄漏查找和解决

Android内存泄漏查找和解决 目录: 内存泄漏的概念 一个内存泄漏的例子 Java中"失效"的private修饰符 回头看内存泄漏例子泄漏的重点 强引用与弱引用 解决内部类的内存泄漏 Context造成的泄漏 使用LeakCanary工具查找内存泄漏 总结 一.内存泄漏概念 1.什么是内存泄漏? 用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元.直到程序结束.即所谓的内存泄漏. 其实说白了就是该内存空间使用完毕之后未回收 2.内存泄漏会导致的问题 内

VMware ESXi中不能显示CPU及内存使用情况的解决方法

今天一个网友问我,他管理的机房有4台ESXi 5.1的服务器,其中三台ESXi Server不能显示各个虚拟机占用的CPU.内存情况了,如图1-1所示. 图1-1在"虚拟机"选项卡中不能显示每个启动虚拟机的资源占用情况 另外,在VMware ESXi的"摘要"中,CPU与内存的使用情况也统计出错,如图1-2所示. 图1-2 摘要统计出错 在出现这个问题时,各个ESXi Server上的虚拟机可以正常启动.关闭,并且各虚拟机运行的系统及应用不受影响. 从上面两个图我看

Erlang服务器内存吃紧的优化解决方法

问题提出:服务器100万人在线,16G内存快被吃光.玩家进程占用内存偏高 解决方法: 第一步: erlang:system_info(process_count). 查看进程数目是否正常,是否超过了erlang虚拟机的最大进程数. 第二步: 查看节点的内存瓶颈所在地方 > erlang:memory(). [{total,2099813400}, {processes,1985444264}, {processes_used,1985276128}, {system,114369136}, {a

Unity3D占用内存太大的解决方法【先转,慢慢看】

Unity3D占用内存太大的解决方法 最近网友通过网站搜索Unity3D在手机及其他平台下占用内存太大. 这里写下关于Unity3D对于内存的管理与优化. Unity3D 里有两种动态加载机制:一个是Resources.Load,另外一个通过AssetBundle,其实两者区别不大. Resources.Load就是从一个缺省打进程序包里的AssetBundle里加载资源,而一般AssetBundle文件需要你自己创建,运行时 动态加载,可以指定路径和来源的. 其实场景里所有静态的对象也有这么一

关于Mysql com.mysql.jdbc.StatementImpl$CancelTask内存泄漏问题及解决办法

近来在负责公司短信网关的维护及建设,随着公司业务发展对短信依赖越来越严重了,短信每天发送量也比以前每天40多w发送量暴增到每天达到200w发送量.因为是采用Java做发送底层,压力递增情况下不可避免的面对内存问题.在发送量接近200w情况下,出现内存泄露问题了. 经过对系统运行检查发现: 1)每次重启系统3-4个小时后,均发现一点不稳定: 2)在3-4个小时后,出现out of memory的错误:java.lang.OutOfMemoryError: GC overhead limit exc