メモリリークについて質問があります。

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
taketoshi
記事: 222
登録日時: 15年前
住所: 日本国

メモリリークについて質問があります。

#1

投稿記事 by taketoshi » 14年前

次のようなコードでメモリ上にデータベースを構築しています。
データベースをリロードする度に、タスクマネージャの物理メモリの使用量がおよそ20MBずつ増えて行っています。
これがメモリリーク?だと思うのですが、対処法が判らずに居ます。。。
それと同時にメモリリークの主たる発生原因もわからずにいます。

これはきちんとメモリを開放出来ているのでしょうか?
また、メモリリークの発生箇所を調べる手法がありましたらご指導願います。

以下がデータベースを構築しているコードです

コード:

/////////////////////////////////////////////////////////////////////////////////////////////////////
//構造体名			:StrageStruct
//機能				:szStrageResultを分割した後の在庫情報を格納する
//					:*SQLサーバー内のテーブルを変更した場合は此処もそれに沿って変更してください
//					:バージョンアップさせても、クライアントとサーバーは同じ構造体を用いること
/////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct{

	unsigned char **lpStrage;			//在庫情報を格納する。配列を動的に確保するのでポインタへのポインタ(ヘッダ情報は含まない)

}DataBase;


/////////////////////////////////////////////////////////////////////////////////////////////////////
//関数名			:CutResult関数
//機能				:メインのResult構造体を更に分解してそれぞれの構造体に格納する
//引数				:Row = 格納したいデータと関連する行数を格納した数値を渡してください
//					:Col = 格納したいデータと関連するカラム数を格納した数値を渡してください
//					:lpDataBase = 目的のデータベースのポインタを渡してください
//					:nSwitch = それぞれに対応するスイッチ番号を渡してください。
//					:			1:在庫情報の切り分け処理 2:出荷情報 3:素板
//戻り値			:動作が完了すると0を返す
//備考				:
/////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename row,typename col,typename DATA>int DataHunger::CutResult(row BaseRow,col BaseCol,DATA **TempData,int nSwitch){

	//strtokが一度でも実行されるとTURE
	BOOL bFlag = FALSE;

	SQLRESULT ResultCopy;
	int i = 0,k = 0;
	int nRow,nCol;
	unsigned char *lpToken,*lpPoint;
	char szBuff[ShipmentSize];
	char *lpStr;


	//strtokで破壊されるので構造体をコピーしておく
	ResultCopy = Result;

	//SQLエラーフラグがTRUEならば処理を中断する
	//あとでインターフェイスを実装してください。
	if(Result.SqlErrorFlag == TRUE){
		//lpStr = CastTimeStr("SQLエラーが検出されました。データが欠損しています。\r\n");
		//SendMessage(HWND_CONTROL::hEdit,EM_REPLACESEL,0,(LPARAM)lpStr);
		return -1;
	}

	//行数とカラム数を取得しておく
	nRow = ntohs(BaseRow);
	nCol = ntohs(BaseCol);

	//行数が0(データ無し)ならリターンする
	if(nRow == 0){
		return -2;
	}

	//構造体の配列を確保する
	*TempData = new DATA[nRow + 3];

	//構造体のメンバ変数をカラム数分確保する
	//nRowに+1することで行数が多い場合のバグを回避
	for(i = 0;i < nRow + 3;++i){
		(*TempData)[i].lpStrage = new unsigned char * [nCol];
	}

	//構造体の全ての配列と、全てのメンバポインタに対して512個の要素数を与える
	//nRowに+1することで行数が多い場合のバグを回避
	for(i = 0;i < nRow + 3;++i){
		for(k = 0;k < nCol;++k){
			(*TempData)[i].lpStrage[k] = new unsigned char[512];
		}
	}

	//変数初期化
	i = 0;
	k = 0;

	//スイッチの切り替え処理
	switch(nSwitch){
		//在庫情報
		case 1:
			strncpy(szBuff,ResultCopy.szStrageResult,sizeof(szBuff));
			break;
		//出荷予定
		case 2:
			strncpy(szBuff,ResultCopy.szShipmentResult,sizeof(szBuff));
			break;
		//素板情報
		case 3:
			strncpy(szBuff,ResultCopy.szBoardResult,sizeof(szBuff));
			break;
		default:
			return -3;
			break;
	}

	//トークンに分解して構造体に格納する
	while(true){
		if(bFlag == FALSE){
			lpToken = _mbstok((unsigned char *)szBuff,(const unsigned char *)"@");
			wsprintf((LPSTR)(*TempData)[i].lpStrage[k],"%s",(LPSTR)lpToken);

			//*注意!!!!!!!!!!!!!!!!!
			//*(*引数)でダブルポインタの実態、すなわちポインタを示す。それにアロー演算子で参照している
			//*わかりずらぃいいいいいいい!!!!!!!!!!!!!!!!!!!!!!
			//MessageBox(NULL,(char *)(*TempData)[i].lpStrage[k],"",MB_OK);
		}else{
			lpToken = _mbstok(NULL,(const unsigned char *)"@");
			//lpTokenがNULLならば抜ける
			if(lpToken == NULL){
				break;
			}else{
				sprintf_s((LPSTR)(*TempData)[i].lpStrage[k],512,"%s",(LPSTR)lpToken);
				//MessageBox(NULL,(char *)(*TempData)[i].lpStrage[k],"",MB_OK);
			}
		}

		bFlag = TRUE;
		k++;
		
		if(k == nCol){
			i++;
			k = 0;
		}
	}
	//後始末
	lpToken = NULL;
	lpPoint = NULL;
	memset(szBuff,0,sizeof(szBuff));
	return 0;
}
以下はメモリを開放するコードです

コード:

/////////////////////////////////////////////////////////////////////////////////////////////////////
//関数名			:ReleaseMemory関数
//機能				:確保したポインタをリリースする
//引数				:
//戻り値			:BOOL型、途中で失敗するとFalse
/////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename row,typename col,typename DATA>int DataHunger::ReleaseMemory(row BaseRow,col BaseCol,DATA **TempData){

	int i,k;
	int nRow;
	int nCol;

	if(*TempData == NULL)
		return false;

	//行数とカラム数を取得しておく
	nRow = ntohs(BaseRow);
	nCol = ntohs(BaseCol);

	//512個の要素をそれぞれ開放
	for(i = 0;i < nRow +3;++i){
		for(k = 0;k < nCol;++k){
			delete[] (*TempData)[i].lpStrage[k];
			(*TempData)[i].lpStrage[k] = NULL;
		}
	}

	//列の要素を開放
	for(i = 0;i < nRow + 3;++i){
		delete[] (*TempData)[i].lpStrage;
		(*TempData)[i].lpStrage = NULL;
	}

	//構造体を開放
	delete[] *TempData;
	*TempData = NULL;
	return true;
}

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: メモリリークについて質問があります。

#2

投稿記事 by ISLe » 14年前

taketoshi さんが書きました:また、メモリリークの発生箇所を調べる手法がありましたらご指導願います。
Visual C++でメモリリークの発生箇所を調べるサンプルプログラムです。
Visual C++ではなかったらごめんなさい。
デバッグ構成でビルドしたとき有効です。

コード:

#include <iostream>

// メモリリークを検出するのに必要な準備
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)

int main()
{
	// プログラム終了時にリークしたメモリブロックの情報を出力ウインドウに出力する設定
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

	new int;
	new char[16];
	return 0;
}

taketoshi
記事: 222
登録日時: 15年前
住所: 日本国

Re: メモリリークについて質問があります。

#3

投稿記事 by taketoshi » 14年前

ありがとうございます。


VisualC++なので、ご提示いただいたコードを試したところ。
出るわ出るわのメモリリークでした。
メモリの開放が上手くいっていないようです。

調べる手段が得られたので
自前でサンプルプログラムを起こして、解明してみます。

閉鎖

“C言語何でも質問掲示板” へ戻る