HEAP[xxx.exe]:Invalid Address specified to RtlValidateHeap 错误的解决方法总结

一、情况一

抽象出问题是这样的:

class DLL_API1 A
{
	func()
	{
		vector vec;
		B b;
		b.func(vec);
		return TRUE;
	}
}


 

其中B是另一个导出类,定义如下

class DLL_API2 B
{
private:
	vector m_vec;
public:
	func( vector &vec )
	{
		vec = m_vec;
	}
}


 

运行时发现,每次运行到A的return TRUE释放vector的时候,都会报错:user breakpoint called from code at  xxxxxxxxxxxxx,并在Debug的提示框中出现:

HEAP[xxx.exe]:Invalid Address specified to RtlValidateHeap    的提示。

网上查了下,基本上都是说是dll和exe在不同的地方开辟了空间,在不同的地方释放的问题。看来以后还需要注意呢。

解决的方法是:

是外层被使用的内存,可以在外层定义后传参到非托管函数,在内部赋值后,在外层被调用,然后被释放;在内部被申请的空间,需在内部显式的的释放,避免造成内存泄露,这样就不会出现上述两种错误。(引用自:http://155134558.blog.163.com/blog/static/22278462009727103058451/

 

也就是说可以做如下修改:

class DLL_API1 A
{
	func()
	{
		B b;
		int nCnt = b.func1();
		 
		vector vec;
		b.func2(vec);

		return TRUE;
	}
}

 

class DLL_API2 B
{
private:
	vector m_vec;
public:
	int func1()
	{
		return m_vec.size();
	}
	func2( vector &vec )
	{
		vec = m_vec;
	}
}



 

不过目前这种解决方案看起来是比较挫啦,不知道能不能从设计上避免。这个问题就先放在这里吧。以后有更多经验的时候再回头看。

二、情况二

遇到该问题的原因是,托管代码和非托管代码之间的分配机制不同,两者之间可以进行互操作,下面是查到的相关内容:

经过一段时间对MSDN的钻研,终于明白C++/CLI互操作共分三种:

1.P/Invoke

2.Com interop

3.C++ interop

我想版主推荐的是指采用C++ interop方式。代码过程如下:

1.将非托管结构和函数放在#pragmaunmanaged内,像这样

#pragma unmanaged 

struct cUserNestedStruct 

{

.........

} ;

extern "C" int DllFunction(UserDefinedStruct**);

2. 然后,在托管代码中就可以直接调用了。

#pragma

managed

int main()

{

UserDefinedStruct*   mystruct = new UserDefinedStruct();

int num = DLLFunction(&mystruct);

}


 

上述是调用Dll,进行互操作的情况。

在我们的项目中,使用托管和非托管混合的方法,通过头文件,直接调用非托管程序。这里需要注意的是:托管代码的内存管理和非托管的内存管理是不同的。在内存堆的分配上也是不同的,所以,两者之间不能直接进行内存的互调用,例如:1,在非托管代码中不能释放托管代码申请的内存;

2,在非托管代码中申请的内存,在函数结束后就被释放,如果被return到托管环境里,是无效的地址。

是外层被使用的内存,可以在外层定义后传参到非托管函数,在内部赋值后,在外层被调用,然后被释放;在内部被申请的空间,需在内部显式的的释放,避免造成内存泄露,这样就不会出现上述两种错误。

本项目中的问题是在非托管代码中,使用了对托管代码中内存块的一个引用,然后在函数结束时,被释放,这样就是free掉了托管代码中申请的内存,会报错,访问无效的内存。

三、情况三

在编译的时候,exe和dll有可能链接的是静态的运行时库,也有可能链接的是dll版本的运行时库。如果在exe或者是dll中有一个链接的是静态的运行时库,那么就会存在两套内存分配的实例。所以在dll中申请的内存,到exe中释放就会失败,因为exe并不认识那块内存。解决的办法就是都使用dll版本的运行时库,这样,在进程空间内,只有一个运行时实例。

 

四、情况四

WCHAR aPathname[]=L"\\\\c:\\pbk_temp";
WCHAR aFilename[]=L"100.dat";
DWORD dwLimitedReadSize=0;
unsigned char* content;
content=NULL;
          .......

dwResult = CONAReadFile(hFS, &FileInfo, content, dwLimitedReadSize, aPathname);
         .........


delete [] content;
content=NULL;


 

 

CONAReadFile是Nokia提供的一个函数,原型为
DWORD CONAReadFile(FSHANDLE hFSHandle, LPCONAPI_FILE_INFO pFileInfo, unsigned char** ppFileData, DWORD dwLimitedReadSize, const WCHAR* pstrTargetPath)

现在我只要一执行delete [] content;程序就崩了。单步跟出现提示信息HEAP[PROPERTYSHEET.exe]: Invalid Address specified to RtlValidateHeap( 00A90000, 00197CC8 )

这是怎么回事?该怎么解决。如果不delete会不会造成内存泄漏。

原因:

在Nokia的库中同时提供了释放char* content的方法,因为char* content指向的内存是由dll中的方法分配的,所以应该由dll中的方法释放。这正好符合C++关于谁分配,谁释放的准侧。
从这个例子,我们可以看到,以后在写dll时,如果在dll中的某个方法内部分配了内存,同时要写一个释放该段内存的方法,对外公开,用来给外部的函数调用

 

五、情况五

我封装了dll 原来是exe 现在封装成dll
发现了这个错误 函数都执行没问题 就是函数执行完 就爆这个错误
我没用dll什么的 就用了string 

调用是

void CTestDlg::OnButton1()  
{    
	// TODO: Add your control notification handler code here     
	UpdateData(TRUE);     
	string ts = m_text;     
	string sData = _ConvertHextoCString(ts);       
	AfxMessageBox(sData.c_str());   
} 


dll封装函数是

#include "stdafx.h" 
#include <string> 
using namespace std;   
BOOL APIENTRY DllMain( HANDLE hModule,   DWORD  ul_reason_for_call, LPVOID lpReserved) 
{     
	return TRUE; 
} 
string ConvertHextoString(string hex) 
{     
	string result;     
	char temp[3];     
	int i = 0;     
	int nLen = hex.length();     
	if (nLen%2 != 0)     
	{         
		return "ERROR";     
	}              
	return result;
}


问题解决了 封装dll 最好类型不要用string 这样很容易有问题
还有就是在传入参数 加上const这样 就保证不会有问题了

 

六、情况六

Dll之间由于由于空间分配和删除引起的

invalid address specified to rtlvalidateheap

在外层模块中定义了一个变量,传入内层模块赋值,用完后在外层模块释放时出错。

 

一个可能的原因:

在不同模块(工程)之间传递 C++ 类,而这两个模块用了不同的运行时库(Runtime Library)设置

例如:EXE 模块调用 DLL 模块里传递 C++ 类的函数,但 DLL 模块使用静态链接(Release 是 Multi-threaded (/MT)、Debug 是 Multi-threaded Debug (/MTd))方式编译,而 EXE 模块使用动态链接(Release 是 Multi-threaded DLL (/MD)、Debug 是 Multi-threaded Debug DLL (/MDd))方式编译。

可以对比这两个模块的工程属性 - C/C++ - Code Generation - Runtime Library,看看设置是否一样,如果不一样要改成一样的。

如果无法解决问题,那就是别的原因了。

 

 

七、情况七

析构函数出问题

调试信息:

HEAP[MHPSO.exe]: Invalid Address specified to RtlValidateHeap( 00390000, 00DAAC68 )
Windows 已在 MHPSO.exe 中触发一个断点。

其原因可能是堆被损坏,这说明 MHPSO.exe 中或它所加载的任何 DLL 中有 Bug

一般是野指针导致。

八、

转载自: http://www.bhcode.net/article/20100713/12048.html

//微粒类
class PARTICLE
{
public:
	double *X;		//微粒的坐标数组
	double *V;		//微粒的速度数组
	double *XBest;	//微粒的最好位置数组
	int Dim;		//微粒的维数
	double Fit;		//微粒适合度
	double FitBest; //微粒最好位置适合度


	//构造函数
	PARTICLE();		//空构造函数
	PARTICLE(int n);//维数为参数的构造函数
	//析构函数
	~PARTICLE();
	void SetDim(int d); //设置微粒的维数
};



//微粒构造函数
PARTICLE::PARTICLE() //空构造函数
{
	X = 0; V = 0; XBest = 0; Dim = 0;
}

PARTICLE::PARTICLE(int n) //维数为参数的构造函数
{
	if(n<0) 
	{
		cout<<"输入有错,维数必须大于0"<<endl;
		return;
	}
	Dim = n;
	X = new double[Dim];
	V = new double[Dim];
	XBest = new double[Dim];
}


//微粒析构函数
PARTICLE::~PARTICLE()
{
	if(Dim)
	{
		delete X;
		delete V;
		delete XBest;
		X=0;
		V=0;
		XBest=0;
	}
}




//定义群粒子类
class PSO
{
public:
	PARTICLE * Particle;	//微粒群数组
	int PNum;				//微粒个数
	int GBestIndex;			//最好微粒索引
	double W;				//惯性权重
	double C1;				//加速度系数1
	double C2;				//加速度系数2
	double *Xup;			//微粒坐标上界数组
	double *Xdown;			//微粒坐标下界数组
	double *Vmax;			//微粒最大速度数组

	void Initialize();		//初始化群体
	void CalFit();			//计算全体适合度
	virtual void ParticleFly(); //微粒飞翔,产生新一代微粒 
	//通讯函数,返回值为false时,系统停止优化
	bool (*Com)(double,		//最优微粒适合度
	double*,				//最优微粒坐标数组
	double**,				//所有微粒坐标指针数组
	int);					//当前最优微粒索引




	//构造函数
	PSO(); //空构造函数
	PSO(int dim, //微粒维数
	int num); //微粒个数
	//析构函数
	~PSO();
};



//PSO构造函数
PSO::PSO()
{
	Particle = 0;
	PNum = 0;
	GBestIndex = 0;
	Xup = 0;
	Xdown = 0;
	W = 1;
	C1 = 2;
	C2 = 2;
	Com = 0;
}


PSO::PSO(int dim, int num)
{
	if(dim<0 || num <0) 
	{
		cout<<"输入有错,维数和粒子个数必须大于0"<<endl;
		return;
	}


	Particle = new PARTICLE[num];
	for(int i=0; i< num; i++) 
		Particle[i].SetDim(dim);
	PNum = num;
	GBestIndex = 0;
	Xup = new double[dim];
	Xdown = new double[dim];
	Vmax = new double[dim];
	W = 1;
	C1 = 2;
	C2 = 2;
	Com = 0;
}



//析构函数
PSO::~PSO()
{
	if(Particle) 
		delete []Particle;
	if(Xup) 
		delete []Xup;//位置上界
	if(Xdown) 
		delete []Xdown;//位置下界
	if(Vmax) 
		delete []Vmax; //速度上下界
	Xup = 0;
	Xdown = 0;
	Vmax = 0;
	Particle=0;
}









//派生多种群分层的PSO类
class MHPSO 
{
public:
	PSO** FirstPso; //第一层多种群粒子群的指针的指针
	int L; //第一层种群的个数 = 第二层粒子群中粒子的个数 
	double C3; //加速度系数3
	PSO* SecondPso;//第二层的粒子群指针
	HANDLE wMutex;
	double Vmin[20] ; //当粒子飞行速度小于Vmin的时,速度变化已不能更新粒子的位置,重新初始化速度
public:
	MHPSO()
	{
		FirstPso=0; L=0; SecondPso=0; C3 = 2;
		for(int i=0;i<20;i++)
		Vmin[i] = 0.0001 ;
		wMutex = ::CreateMutex(NULL,false,NULL);
	}

//构造函数,给出微粒维数n 和种群个数L,种群中粒子的个数m
MHPSO(int n, int m,int L)
{
	this->L = L;
	FirstPso = new PSO*[L];
	for(int i=0 ;i< L;i++)
		FirstPso[i] = new PSO(n,m);


	SecondPso = new PSO(n,L); 
	C3 = 2;
	for(int i=0;i<20;i++)
		Vmin[i] = 0.0001 ;
	wMutex = ::CreateMutex(NULL,false,NULL);
} 


~MHPSO()
{
	for(int i=0;i<L;i++)
	{
		delete this->FirstPso[i];
		this->FirstPso[i] =0;
	}

	delete []FirstPso;
	this->FirstPso = 0;

	delete SecondPso; 
	SecondPso =0; //这两句有问题。。。,如果去掉程序就不会出错。。
	::CloseHandle(wMutex);
}

}; 



 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值