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的差别
MFC多线程内存泄漏问题&解决方法的更多相关文章
- 上Mysql com.mysql.jdbc.StatementImpl$CancelTask内存泄漏问题和解决方法
近来在负责公司短信网关的维护及建设,随着公司业务发展对短信依赖越来越严重了,短信每天发送量也比曾经每天40多w发送量暴增到每天达到200w发送量.由于是採用Java做发送底层,压力递增情况下不可避免的 ...
- Android 内存泄漏分析与解决方法
在分析Android内存泄漏之前,先了解一下JAVA的一些知识 1. JAVA中的对象的创建 使用new指令生成对象时,堆内存将会为此开辟一份空间存放该对象 垃圾回收器回收非存活的对象,并释放对应的内 ...
- 使用HandyJSON导致的内存泄漏问题相关解决方法
在移动开发中,与服务器打交道是不可避免的,从服务器拿到的接口数据最终都会被我们解析成模型,现在比较常见的数据传输格式是json格式,对json格式的解析可以使用原生的解析方式,也可以使用第三方的,我们 ...
- Android开发之漫漫长途 番外篇——内存泄漏分析与解决
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
- Android开发 |常见的内存泄漏问题及解决办法
在Android开发中,内存泄漏是比较常见的问题,有过一些Android编程经历的童鞋应该都遇到过,但为什么会出现内存泄漏呢?内存泄漏又有什么影响呢? 在Android程序开发中,当一个对象已经不需要 ...
- 5个Android开发中比较常见的内存泄漏问题及解决办法
android中一个对象已经不需要了,但是其他对象还持有他的引用,导致他不能回收,导致这个对象暂存在内存中,这样内存泄漏就出现了. 内存泄漏出现多了,会是应用占用过多的没存,当占用的内存超过了系统 ...
- Linux系统内存占用90%以上——解决方法
Linux系统内存占用90%以上--解决方法 首先要明确一个问题:Linux系统内存占用90%以上,是否属于正常范围?网上有详细的解释,这属于正常现象~~~ www.2cto.com L ...
- 内存泄漏之malloc替换方法
//内存泄漏之malloc替换方法 //内存泄漏之malloc替换方法#include "stdio.h"#include "stdlib.h" /*文件路径名 ...
- Java虚拟机系列(三)---内存溢出情况及解决方法
因为Java虚拟机内存有堆内存.方法区.虚拟机栈.本地方法栈和程序计数器五部分组成,其中程序计数器是唯一一块不会发生内存溢出异常的内存区,所以只有四类内存区可能发生内存溢出异常,其中虚拟机栈和本地方法 ...
随机推荐
- 盒子模型&position定位
有时候深深的感觉语文这门课程其实很有用, 至少以前学的时候没有感觉到 直到现在阅读大量的别人的资料文章的时候或者是看一些题目....... 总之:认真阅读小心品味 当然,前面的孤言自语和本文无关,只是 ...
- MFC读写配置文件
void CFileTextDoc::OnIniread() { // TODO: Add your command handler code here CString strStudName; ...
- JavaScript --------------继前面继承方式-------总结
创建对象方式: 工厂模式:使用简单的函数创建对象,为对象添加属性和方法,然后返回对象: function createPerson(name,age,job){ var o = new Object( ...
- VB短信猫开发包,支持超长短信
一.短信猫开发包(长短信/异步调用)说明: 短信猫开发包以OCX控件的形式提供,支持Windows平台下常用的开发工具:如VB.VB.net.VC++.Power Builder.C#.DELPH ...
- 关于Ajax技术中servlet末尾的输出流
Ajax的服务器端用PrintWriter out=resp.getWriter()来响应数据的时候,out.print(0).out.print(1)来表示成功或失败,而不用out.write是有原 ...
- BZOJ 2882 工艺 (字符串最小循环同构)
题目大意: 给一个长度小于等于30W的数列,求其最小循环同构. 算法讨论: 在自动机长倍长走S后即可.注意这里面是数字,要用map存储. 今天才知道要开四倍长. Codes: #include < ...
- main()和_tmain()有什么区别
用过C的人都知道每一个C的程序都会有一个main(),但有时看别人写的程序发现主函数不是int main(),而是int _tmain(),而且头文件也不是<iostream.h>而是&l ...
- MySQL 初学笔记 ① -- MySQL用户登录权限控制
1. MySQL 登录 MySQL -u username -p 2. MySQL 创建用户 use mysql //进入mysql 表 INSERT INTO user (Host,User,Pas ...
- HTML5 JavaScript 文件上传
function fileUpload(targetUrl) { // 隐藏表单名称 var inputName = '_fileselect'; // 文件尺寸 this.fileSize = 0; ...
- table列等宽
固定table列等宽 固定table列等宽 style: {table-layout : fixed} html: style="table-layout:fixed" js: o ...