我编了一个服务器程序,多线程,在测试的时候没有发现内存泄漏,但是在实际应用中,发现较长一段时间后,程序占用了大量的虚拟内存。最近发现是在处理throw try catch异常事务时出现的,通过简单的编程测试可以证实throw try catch语句的内存泄漏问题,求教高手有什么好的解决方案?
测试例程如下:
对于throw try...catch...语句,存在内存泄漏问题:如果是使用堆栈内存,不存在内存泄漏问题,但如果是使用堆内存,就存在内存泄漏问题。
测试例程
#include <iostream.h>
#include <windows.h>
#include <string>
#include <malloc.h>
class AA
{
private:
char * buff;
public:
AA():buff(NULL){}
~AA()
{
if(buff!=NULL)
delete buff;
}
void Init(){buff = new char[10240];}
};
void test(void)
{ //会产生内存泄漏,因为aa.Init()中分配了堆内存,在throw时内存来不及释放。
AA aa;
aa.Init();
throw "test_error ";
return ;
}
void test2(void)
{ //不会产生内存泄漏,因为buff使用的是堆栈内存,在函数结束时清理堆栈将自动清理堆栈
char buff[10240];
throw "test_error2";
return ;
}
void test3(void)
{ //会产生内存泄漏,因为new中分配了堆内存,在throw时内存来不及释放。
char *buff;
buff = new char[10240];
throw "test_error2";
delete buff;
return;
}
void test4(void)
{ //会产生内存泄漏,因为aa=".."中分配了堆内存,在throw时内存来不及释放。(证明标准的C++类也存在同样的内存泄漏问题。)
std::string aa;
aa = "kasdfasdfasdfaksldfjas;lkasdjg;laksdjg;alskdjgf;alskdjf;alksjd;kgjas;dlkjfalskjdhlkasjghlaksdjhglaskdjgfashdkjlg";
throw "test_error ";
return ;
}
void test5(void)
{ //不会产生内存泄漏,因为_allca使用的是堆栈内存,在函数结束时清理堆栈将自动清理堆栈,所以该内存的有效使用范围只在本函数内,而且不能使用free释放内存。
char * buff;
buff = (char *)_alloca(1024);
throw "test_error5";
return ;
}
int main(void)
{
for(int i=0;i<10000;i++)
{
try{
test5();
}
catch(const char *ser)
{
}
cout << i << "\r";
Sleep(10);
}
return 0;
}
如果需求保证内存泄漏问题,需要管理内存链表,在catch事务处理中进行内存检查和回收。但是在多线程程序中比较难以处理。
如:
class bb
{
private:
MyMemoryList *p;
public:
bb(); --> p->Add(this); // 增加到管理链表
~bb(); --> p->Del(this); // 从链表中删除,如果碰到throw来不及删除,将在p中留下记录。
}
另一种方法是在碰到throw时,把因该清除的内存清理干净。这样做的难度比较大。
测试例程如下:
对于throw try...catch...语句,存在内存泄漏问题:如果是使用堆栈内存,不存在内存泄漏问题,但如果是使用堆内存,就存在内存泄漏问题。
测试例程
#include <iostream.h>
#include <windows.h>
#include <string>
#include <malloc.h>
class AA
{
private:
char * buff;
public:
AA():buff(NULL){}
~AA()
{
if(buff!=NULL)
delete buff;
}
void Init(){buff = new char[10240];}
};
void test(void)
{ //会产生内存泄漏,因为aa.Init()中分配了堆内存,在throw时内存来不及释放。
AA aa;
aa.Init();
throw "test_error ";
return ;
}
void test2(void)
{ //不会产生内存泄漏,因为buff使用的是堆栈内存,在函数结束时清理堆栈将自动清理堆栈
char buff[10240];
throw "test_error2";
return ;
}
void test3(void)
{ //会产生内存泄漏,因为new中分配了堆内存,在throw时内存来不及释放。
char *buff;
buff = new char[10240];
throw "test_error2";
delete buff;
return;
}
void test4(void)
{ //会产生内存泄漏,因为aa=".."中分配了堆内存,在throw时内存来不及释放。(证明标准的C++类也存在同样的内存泄漏问题。)
std::string aa;
aa = "kasdfasdfasdfaksldfjas;lkasdjg;laksdjg;alskdjgf;alskdjf;alksjd;kgjas;dlkjfalskjdhlkasjghlaksdjhglaskdjgfashdkjlg";
throw "test_error ";
return ;
}
void test5(void)
{ //不会产生内存泄漏,因为_allca使用的是堆栈内存,在函数结束时清理堆栈将自动清理堆栈,所以该内存的有效使用范围只在本函数内,而且不能使用free释放内存。
char * buff;
buff = (char *)_alloca(1024);
throw "test_error5";
return ;
}
int main(void)
{
for(int i=0;i<10000;i++)
{
try{
test5();
}
catch(const char *ser)
{
}
cout << i << "\r";
Sleep(10);
}
return 0;
}
如果需求保证内存泄漏问题,需要管理内存链表,在catch事务处理中进行内存检查和回收。但是在多线程程序中比较难以处理。
如:
class bb
{
private:
MyMemoryList *p;
public:
bb(); --> p->Add(this); // 增加到管理链表
~bb(); --> p->Del(this); // 从链表中删除,如果碰到throw来不及删除,将在p中留下记录。
}
另一种方法是在碰到throw时,把因该清除的内存清理干净。这样做的难度比较大。