天天看點

HEAP[xxx.exe]:Invalid Address specified to RtlValidateHeap 錯誤的解決方法總結

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);
}

};