1. 什么叫内存泄漏?
内存泄漏是指你分配了内存,使用完毕后没有正确释放它。这样这个内存就不能再被使用。
例如:
void test()
{
char * p = new char[MAX_PATH];
GetModuleFileName(NULL,p, MAX_PATH);
strcat(p+strlen(p) - 3, "txt");
CStdioFile file(p);
file.WriteString("text");
file.Close();
}
注意:上面的指针p函数退出后就无法再释放,new char[MAX_PATH]分配的内存就泄漏了。
2. 何时我的程序泄漏了?
从外部看,我们很难100%准确的方法去判断是否有内存泄漏。实际上,一块内存是否被泄漏,从外部看只有当进程结束才能知道。因为你完全可以从开始分配一块内存,直到结束才去释放它。
基本上,下面行为不能说明内存泄漏:
a) 任务管理器上显示内存使用增加了1MB
b) 内存使用很多(我见过最大内存使用超过1.5GB的程序)
下面行为可能意味着有内存泄漏:
a) 一个进程的内存使用量按照一个固定的速度稳定的增长(例如每小时增加20MB)
如果可以在VC IDE中运行程序,当程序退出时,系统会报一堆泄漏错误。
3. 如何定位
从编译器角度讲,在分配内存后,任何时候释放都是合适的,因此系统不会知道你何时适合去释放内存。在进程运行过程中,你只能估计是否有内存泄漏,而不能确定一定有内存泄漏。一般来说,我们可以用以下一些办法定位:
a) 使用性能监视器跟踪进程的内存使用情况,如果它在不断增长,且增长速度趋于稳定,一般说明在某个循环性的操作中有内存泄漏
b) 在编译器中按照Debug模式运行程序,运行一定时间后(例如2天),使用正常的方式停止进程
正常情况下,你不会收到任何和内存有关的异常。如果你程序有内存泄漏,你会收到如下错误信息:
Detected memory leaks!
Dumping objects ->
D:\projects\EnumWnd\EnumWndDlg.cpp(185) : {78} normal block at 0x00421330, 100 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
注意,这里EnumWndDlg.cpp(185)应该是分配这块内存的地方。这是因为没有所谓的内存泄漏点,只有在某点分配的内存被泄漏了。
4. 如何分析内存泄漏
内存泄漏分析一般是通过分析内存生命周期来进行的。你必须对你的内存的可能使用情况有所了解。在此基础上,你应该了解在那个地方内存应该被释放。如果有内存泄漏,说明程序没有走到那个地方,或者释放代码没有正确执行。因此你可能需要跟踪你代码的执行情况,通过分析为什么代码没有按照预期走到内存释放处,了解为什么内存泄漏了。
常见的原因:
a) 忘记释放
b) 释放的方法错误
例如:把指针加入诸如CArray之类的集合对象中,释放时应该首先通过delete操作删除指针指向的对象,然后才能去调用诸如RemoveAll函数去释放集合中的指针。单纯析构诸如CArray之类的对象,不会自动释放它所包含的指针所指向的对象。
c) 析构函数错误:如果你对象中包含指针,那么你析构函数需要正确的释放这些指针。如果你析构函数不做这些,就会有内存泄漏
d) 线程问题:如果线程被你通过TerminateThread中止,那么它所分配的对象一般不会有机会被释放。这是那些喜欢在线程外中止线程的人经常遇到的问题。
顺便说一句:现有的工具很多都是基于猜测的基础上进行内存泄漏检测的,很有帮助但是不能全信。内存泄漏分析主要还是得基于源码分析
1。尽量使用C++标准模板容器,它们是可信任的。
比如字符串
a. 对于不用于传给API改写的字符串,尽量使用string
b. 对于需要传给API改写的字符串,尽量使用vector<char>,使用前先调用 vector.resize();
2。对于单个堆变量,使用 auto_ptr
3。对于一组堆变量,使用 vector
4。(这一点仅对那些一窍不通且又顽劣不化者说)没事少new点。
5。(这一点仅对那些一窍不通且又顽劣不化者说)在标准容器中别放指针,除非你能肯定它不需要你释放。
对于楼主的代码,我会这样写:
#include <iostream>
#include <vector>
#include <fstream>
#include <windows.h>
void test()
{
using namespace std;
vector<char> str( MAX_PATH ); // 当然 char str[MAX_PATH] 是最好的选择
char* p = &str[0]; // 在str改变容量大小前,p都是有效的。
GetModuleFileNameA( NULL, p, MAX_PATH ); // 这一句省略正确性判断
strcpy( p+strlen(p)-3, "txt"); // 不知道你用strcat是干什么,我把它改为strcpy了
ofstream file( p );
file << "test";
file.close();
}
还是用boundcheck吧。
这此工具应该不是纯粹猜测,他们中可能只是重载了new,delete,还有其他的内存分配函数。
代码一多,你想基于原代码分析,谈何容易啊。
bc连你createhandle泄漏都捕获得到。
美孚、壳牌、长城、埃索、力士、UP、润滑油N-甲基吡咯烷酮(nmp)
- 访问:46663次
- 积分:440分
- 排名:第23名
- 随笔:44篇
- 评论:578条
随笔分类
随笔归档
个人相册
阅读排行榜
- 内存访问越界 (5049)
- 粘包、丢包及TCP信息收发 (3305)
- 内存泄漏问题分析 (2480)
- 汇款失败也收手续费 - 记我在招商银行的一次失败的维权经历 (1641)
- 最大化、最小化和关闭按钮 (1468)
- 欧几里德算法和扩展欧几里德算法 (1444)
- 基类定义了operator new,派生类有什么需求 (1374)
- Stein算法,另外一个计算最大公约数的方法 (1350)
- 中国余数定理(CRT)及其应用 (1344)
- 句柄和ID (1286)
评论排行榜
- 内存泄漏问题分析 (172)
- 句柄和ID (32)
- 欧几里德算法和扩展欧几里德算法 (26)
- Stein算法,另外一个计算最大公约数的方法 (25)
- 欧拉函数公式 (23)
- 质数初步 (21)
- 最大化、最小化和关闭按钮 (21)
- 超女随感 (17)
- 内存访问越界 (15)
- 汇款失败也收手续费 - 记我在招商银行的一次失败的维权经历 (13)
最新评论
- 粘包、丢包及TCP信息收发
Dennisweri:?
- 粘包、丢包及TCP信息收发
boli:re: 粘包、丢包及TCP信息收发 刀哥. send 涵数在阻塞模式下是发多...
- 粘包、丢包及TCP信息收发
nscby:re: 粘包、丢包及TCP信息收发 理解的TCP数据流的概念就不难弄清除粘包和丢包的概念了. TC...
- 粘包、丢包及TCP信息收发
advice:re: 粘包、丢包及TCP信息收发 好好读读richard的书 完全不懂网络
- 内存访问越界
qq:358524789:re: 内存访问越界 破坏其他变量的内存情况,是变量前的还是后的,要看CPU的大小端模式才能确定!
- 内存访问越界
平凡:re: 内存访问越界 不得不说严谨的编程习惯是多么的重要。谢谢阿荣的讲解。
- 内存访问越界
gaojl0728:re: 内存访问越界 内存越界还跟堆栈的增长方式有关,一般的cpu堆栈都是向下增长的,所以你第二个...
- 内存访问越界
pxd:re: 内存访问越界 谢谢 学习了
- 内存访问越界
大虾米(dxm)的技术博客:re: 内存访问越界 语重心长,VC老程序员啊
- 内存访问越界
fastzhao:re: 内存访问越界 可以用Flags查出内存越界