1. 程式人生 > >頻繁通過win32api的createfile函式開啟檔案控制代碼導致記憶體洩漏

頻繁通過win32api的createfile函式開啟檔案控制代碼導致記憶體洩漏

1、通過win32的createfile、writefile函式開啟寫入檔案

void WriteLogThread(void* lpParameter)
{
	LPLogData pData = (LPLogData)lpParameter;
	string logContent=pData->logContent;
	string logType=pData->logType;
	//釋放傳參所分配的堆記憶體
	//HeapFree(GetProcessHeap(), 0, pData);
	delete pData;

	string strPath="C:\\HttpServerLog";
	WIN32_FIND_DATAA wfd;
	HANDLE hFind = FindFirstFileA(strPath.c_str(),&wfd);
	if (hFind == INVALID_HANDLE_VALUE)
	{
		//目錄不存在
		CreateDirectoryA(strPath.c_str(), NULL);
	}
	FindClose(hFind);

	HANDLE hFile;
	string fileName="C:\\HttpServerLog\\HttpServerLog"+GetData()+".html";
	do 
	{
		hFile = CreateFileA(fileName.c_str(),     //建立檔案的名稱。
			GENERIC_WRITE|GENERIC_READ,          // 寫和讀檔案。
			0,                      // 不共享讀寫。
			NULL,                   // 預設安全屬性。
			OPEN_ALWAYS,          // 總開啟檔案,如不存在,則建立
			FILE_ATTRIBUTE_NORMAL, // 一般的檔案。      
			NULL); // 模板檔案為空。

		//檔案被佔用時
		if(hFile == INVALID_HANDLE_VALUE)
		{
			Sleep(500);//等待500毫秒
		}
	} while (hFile == INVALID_HANDLE_VALUE);

	//設定寫入位置
	LONG lDistance = 0;
	SetFilePointer(hFile, lDistance, NULL, FILE_END);

	//往檔案裡寫資料
	string str= "";

	if(logType=="Error")
	{
		str= "<hr>\r\n<h5 style='color:red'>["+logType+"]"+GetDataTime()+"</h5>\r\n<h6 style='color:red'>"+logContent+"</h6>\r\n";
	}
	else
	{
		str= "<hr>\r\n<h5 style='color:blue'>["+logType+"]"+GetDataTime()+"</h5>\r\n<h6 style='color:blue'>"+logContent+"</h6>\r\n";
	}
	int len = lstrlenA(str.c_str());
	DWORD dwWritenSize = 0;
	BOOL bRet = WriteFile(hFile,str.c_str(),len,&dwWritenSize,NULL);

	//先把寫檔案緩衝區的資料強制寫入磁碟。
	FlushFileBuffers(hFile);
	//關閉檔案
	CloseHandle(hFile);
}
因為寫檔案是開執行緒寫的,故寫了個迴圈用於等待獲取檔案控制代碼,當檔案被佔用時,就會一直迴圈等等。獲取到檔案控制代碼後,再呼叫writefile執行檔案寫入。

因為程式有記憶體洩漏問題,即某些記憶體沒有釋放掉,故跟蹤程式碼發現在迴圈createfile這個函式中會存在記憶體洩漏,應該是控制代碼洩漏。

正常開啟檔案控制代碼後,通過closehandle函式應該能釋放掉檔案控制代碼以及佔用的記憶體。但是測試結果就是不行。

2、最後實在找不到原因,懷疑就是win32自身的問題,迫不得已換一種寫法用ofstream來寫入檔案,需要引用標頭檔案#include <fstream>

void WriteLogThread(void* lpParameter)
{
	LPLogData pData = (LPLogData)lpParameter;
	string logContent=pData->logContent;
	string logType=pData->logType;
	//釋放傳參所分配的堆記憶體
	//int a =HeapFree(GetProcessHeap(), 0, pData);
	delete pData;

	string strPath="C:\\HttpServerLog";
	WIN32_FIND_DATAA wfd;
	HANDLE hFind = FindFirstFileA(strPath.c_str(),&wfd);
	if (hFind == INVALID_HANDLE_VALUE)
	{
		//目錄不存在
		CreateDirectoryA(strPath.c_str(), NULL);
	}
	FindClose(hFind);

	string fileName="C:\\HttpServerLog\\HttpServerLog"+GetData()+".html";

	//利用ofstream進行寫操作
	//輸出流,把流輸出到儲存裝置
	//ios::in	為輸入(讀)而開啟檔案
	//ios::out	為輸出(寫)而開啟檔案
	//ios::ate	初始位置:檔案尾
	//ios::app	所有輸出附加在檔案末尾
	//ios::trunc	如果檔案已存在則先刪除該檔案
	//ios::binary	二進位制方式
	ofstream out;
	out.open(fileName.c_str(),ios::out|ios::app);
	while(!out.is_open())
	{
		Sleep(5000);
		out.open(fileName.c_str(),ios::out);
	}

	string str= "";
	if(logType=="Error")
	{
		str= "<hr>\r\n<h5 style='color:red'>["+logType+"]"+GetDataTime()+"</h5>\r\n<h6 style='color:red'>"+logContent+"</h6>\r\n";
	}
	else
	{
		str= "<hr>\r\n<h5 style='color:blue'>["+logType+"]"+GetDataTime()+"</h5>\r\n<h6 style='color:blue'>"+logContent+"</h6>\r\n";
	}

	out<<str.c_str();
	out.close();
}
建議對檔案進行讀寫操作,儘量使用ofstream、ifstream等c++的庫。儘量windows作業系統提供的createfile函式