在用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的差别


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

  1. 上Mysql com.mysql.jdbc.StatementImpl$CancelTask内存泄漏问题和解决方法

    近来在负责公司短信网关的维护及建设,随着公司业务发展对短信依赖越来越严重了,短信每天发送量也比曾经每天40多w发送量暴增到每天达到200w发送量.由于是採用Java做发送底层,压力递增情况下不可避免的 ...

  2. Android 内存泄漏分析与解决方法

    在分析Android内存泄漏之前,先了解一下JAVA的一些知识 1. JAVA中的对象的创建 使用new指令生成对象时,堆内存将会为此开辟一份空间存放该对象 垃圾回收器回收非存活的对象,并释放对应的内 ...

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

    在移动开发中,与服务器打交道是不可避免的,从服务器拿到的接口数据最终都会被我们解析成模型,现在比较常见的数据传输格式是json格式,对json格式的解析可以使用原生的解析方式,也可以使用第三方的,我们 ...

  4. Android开发之漫漫长途 番外篇——内存泄漏分析与解决

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

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

    在Android开发中,内存泄漏是比较常见的问题,有过一些Android编程经历的童鞋应该都遇到过,但为什么会出现内存泄漏呢?内存泄漏又有什么影响呢? 在Android程序开发中,当一个对象已经不需要 ...

  6. 5个Android开发中比较常见的内存泄漏问题及解决办法

    android中一个对象已经不需要了,但是其他对象还持有他的引用,导致他不能回收,导致这个对象暂存在内存中,这样内存泄漏就出现了.   内存泄漏出现多了,会是应用占用过多的没存,当占用的内存超过了系统 ...

  7. Linux系统内存占用90%以上——解决方法

    Linux系统内存占用90%以上--解决方法   首先要明确一个问题:Linux系统内存占用90%以上,是否属于正常范围?网上有详细的解释,这属于正常现象~~~    www.2cto.com   L ...

  8. 内存泄漏之malloc替换方法

    //内存泄漏之malloc替换方法 //内存泄漏之malloc替换方法#include "stdio.h"#include "stdlib.h" /*文件路径名 ...

  9. Java虚拟机系列(三)---内存溢出情况及解决方法

    因为Java虚拟机内存有堆内存.方法区.虚拟机栈.本地方法栈和程序计数器五部分组成,其中程序计数器是唯一一块不会发生内存溢出异常的内存区,所以只有四类内存区可能发生内存溢出异常,其中虚拟机栈和本地方法 ...

随机推荐

  1. jquery常用方法以及详解

    $("p").addClass(css中定义的样式类型); 给某个元素添加样式 $("img").attr({src:"test.jpg", ...

  2. 实现Android操作系统11种传感器介绍

    在Android2.3 gingerbread系统中,google提供了11种传感器供应用层使用. #define SENSOR_TYPE_ACCELEROMETER 1 //加速度 #define ...

  3. bad interpreter: No such file or directory

    经常会遇到这种情况,在windows下写的脚本,代码会在linux下无法执行,错误就是: bad interpreter: No such file or directory 1.原因 这通常都是由于 ...

  4. VS2012 拆分视图按钮不见,代码,设计

    工具--选项--HTML设计器 然后重启就有了.

  5. 怎么实现类似星星闪烁的效果(box-shadow)

    有时候设计希望我们能够在页面实现类似星星闪烁的效果,如图: 我的解决办法是用box-shadow: html <div class="star04 active-blink" ...

  6. Android开发记录(转)

    一.Android模拟器相关 1. Android模拟器安装 Market 模拟器默认没有安装 Market,看到网上有较为复杂的安装方法,也有1个简单的,试了简单的,在 Android2.2 模拟器 ...

  7. HTTPS那些事(一) HTTPS原理

    谣言粉碎机前些日子发布的<用公共WiFi上网会危害银行账户安全吗?>,文中介绍了在使用HTTPS进行网络加密传输的一些情况,从回复来看,争议还是有的.随着网络越来越普及,应用越来越广泛,一 ...

  8. T-SQL 函数概述

    T-SQL函数的类别和描述: 函数类别 作用 聚合函数 返回一个标量值,表示在某个值域上的聚合,应用于特定的聚合选择或者汇总 配置变量 返回SQL Server执行环境的信息.这些信息可用于给对象编程 ...

  9. UIAlertView与UIActionSheet

    1.UIAlertView(警告框) 1.1 创建警告框,设置样式 - (IBAction)alertView:(UIButton *)sender {//创建button按钮 //创建警告框的实例 ...

  10. BZOJ 2176 Strange String (最小表示法)

    题目大意: 与别的裸题的唯一不同点是其符号的ASCII码值在3 ~ 254 之间. 算法讨论: 最小表示法直接上.但是唯一不同的就是注意这里的字符范围,用char是会get wa的,所以要用unsig ...