阅读:2664回复:10
线程造成内存泄露?
我在WIN32 DLL中用CreateThread()函数创建了一个线程,在线程中要使用一个64kbytes的堆空间,通过传给线程。函数线程能够正确的运行,但是当退出调用线程的程序后,出现了内存泄露的情况。
在线程中,我已经用delete函数释放了分配的64kbytes的空间,可是,他说还剩下45Bytes的空间释放,出现内存泄露,请问这个应如和解决好啊?谢谢各位拉! |
|
沙发#
发布于:2004-06-08 08:29
你说的不大清楚,内存什么时候,在哪申请和释放
建议: 一般使用C\C++运行期库函数_beginthreadex可以避免这种问题, 或者你用线程同步,在适当的时候释放内存, |
|
|
板凳#
发布于:2004-06-08 08:55
在主线程中用GETEXITCODETHREAD来监控线程,当其退出后,在主线程中释放内存.
|
|
|
地板#
发布于:2004-06-08 12:55
在要调用线程的主函数中分配64kBytes内存,然后,在把内存的地址传给在dll中的线程,当终止dll中线程的运行时,由dll中被调用的线程释放内存。
我使用了CC++运行期库函数_beginthreadex还时遇到了上述的问题阿。我发现在主线程中用malloch和new来分配内存还是存在内存泄漏的情况,但是,在主线程中用 GlobalAlloc()和HeapAlloc()时能够暂时防止内存泄漏。这是怎么的一回事啊? 使用了CC++运行期库函数_beginthreadex来创建线程,在线程中使用malloc和new函数分配内存,应该不会在产生内存泄漏才对阿!这又是怎么的一回事? 再次,问一下使用_beginthreadex创建的线程,当调用他的主程序退出时,如果不显示的调用一些函数来终止线程的话,CC++运行期库能够自动调用_endthreadex()函数来终止线程的运行,是这样的么? |
|
地下室#
发布于:2004-06-08 13:10
DLL导出函数尊从__declspec调用约定,按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的。所以,你不能在DLL函数中释放内存,只能在调用该函数的主程序中释放的内存,即:
谁分配,谁释放; 谁污染,谁治理。 |
|
|
5楼#
发布于:2004-06-08 13:15
线程同步,WOWOCOCK的方案是可行的方案
|
|
|
6楼#
发布于:2004-06-08 17:03
你的意思是不是,只要是传给DLL引出函数的指针,就只能够在只能在调用该函数的主程序中释放的指针?
那么我这里还有个问题,我要写的那个线程要不停的调用driver中的函数,从硬件设备读数据。那个线程能够不停的从设备读数据,要把数据不停的存放到应用程序传给线程的那个缓冲区。 如果缓冲区的由调用读数据的线程来维护、释放,当调用了创建线的函数过后,调用函数就退出了的嘛,缓冲区也就被释放了。读数据的线程就回读数据失败!这个问题你们没有什么好的注意啊? 下面有我的原代码。 |
|
7楼#
发布于:2004-06-08 17:03
我的主要代码如下,你们帮我看看有什么不足,和错误,需要改正的!
谢谢! 在动态连接库中, 线程函数的定义如下: typedef struct DataInfo{ ULONG dwDSPAddr; PULONG ReturnAddr; ULONG ReturnBufSize; PULONG pReturnLength; HANDLE *pEvent; }*PDataInfo; unsigned __stdcall ServiceThread(PVOID Param) { PDataInfo pRead = (PDataInfo)Param; //Open device ........................ //传递事件 ............................. while(TRUE) { //WaitForSingleObject(hEvent,INFINITE); DWORD flag=0; while((flag=WaitForSingleObject(hEvent,0))!= WAIT_OBJECT_0) { if(!(*pRead->pKeepRunning)) { //应用程序开辟的缓冲区,传给线程的地址线程退出时释放 delete pRead->ReturnAddr; delete pRead; CloseHandle(hDevice); CloseHandle(hEvent); return 0; } } ULONG ReturnWrite = 0; BOOL bResult = FALSE; if(WriteFile(hDevice, &pRead->dwDSPAddr, 4, &ReturnWrite, NULL )) bResult = ReadFile(hDevice, pRead->ReturnAddr, pRead->ReturnBufSize, pRead->pReturnLength, NULL ); else bResult = FALSE; if(bResult == FALSE) { delete pRead->ReturnAddr; delete pRead; pRead = NULL; MessageBox(NULL,"取数据失败!","失败!",MB_OK); return 0; }else { if(SetEvent(*(pRead ->pEvent))) MessageBox(NULL,"SetEvent","",MB_OK); } } //应用程序开辟的缓冲区,传给线程的地址线程退出时释放 free(pRead->ReturnAddr); delete pRead; pRead = NULL; return 0; } C6416DLL_API HANDLE CALLBACK GetDSPData(ULONG dwAddr, PULONG Buf, ULONG BufSize, PULONG pLengthByRead, HANDLE *pEvent ) { unsigned ThreadId; HANDLE hThread = NULL; //准备取数据缓冲区 PDataInfo pInfo = new(DataInfo); pInfo->dwDSPAddr = dwAddr; pInfo->ReturnBufSize = BufSize; if((pInfo->ReturnBufSize) > 0x10000) pInfo->ReturnBufSize = 0xffff; pInfo->ReturnAddr = Buf; if(pInfo->ReturnAddr == NULL) { MessageBox(NULL,"缓冲区不存在!","失败!",MB_OK); return false; } pInfo ->pReturnLength = pLengthByRead; pInfo ->pEvent = pEvent; hThread = (HANDLE)_beginthreadex(0, 0x1000, ServiceThread, (PDataInfo)pInfo, 0, &ThreadId); if(hThread == NULL) { delete pInfo->ReturnAddr; delete pInfo; pInfo = NULL; MessageBox(NULL,"创建线程失败!","失败!",MB_OK); } return hThread; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 在应用程序中调用dll中创建的线程: void CTestC6416Dlg::OnDma() { ULONG dwAddrDSP = 0x10000; ULONG nSize = 0xffff; ULONG LengthByRead = 1; // PULONG ResultAddr = (PULONG)malloc(nSize); // PULONG ResultAddr = (PULONG)new ULONG(nSize); // PULONG ResultAddr = (PULONG)GlobalAlloc(0,nSize); PULONG ResultAddr = (PULONG)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,nSize); if(ResultAddr == NULL) { AfxMessageBox("内存分配失败!"); return; } //创建事件对象用于读数据同步 HANDLE hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); if(hEvent == NULL) { AfxMessageBox("创建事件对象失败!"); return; } //调用dll中的GetDSPData()函数创建线程,线程不停的从设备取数每次64kBytes hThread = GetDSPData(dwAddrDSP,ResultAddr,nSize,&LengthByRead,&hEvent); if(hThread == NULL) { AfxMessageBox("调用失败!"); return; } while(WaitForSingleObject(hEvent,INFINITE) == WAIT_OBJECT_0) { //显示头4个字节的数据 m_strData.Format("%x",*(ResultAddr)); CDialog::UpdateData(false); ResetEvent(hEvent); } } 我的线程如上定义的,不能够在ServiceThread线程中释放由CTestC6416Dlg::OnDma()分配的内存么? 那我还就是怎样才能够让我的线程能够终止运行? 能不能够在线程中设置一个bool值的变量,线程去检测这个变量的值,如果是指示要退出线程, 那么用上面的方式--采用return语句能够终止线程的运行么?他拥有的资源也能够释放么? |
|
8楼#
发布于:2004-06-09 08:55
也不完全是
关键看你的调用约定 总共三种调用约定,你自己看看资料 我说过 线程同步可以解决你的问题 你自己试一下 我就不分析你的代码了 |
|
|
9楼#
发布于:2004-06-09 11:05
建议你去看看 Jeffer Richter那本经典名著
programming AP for windows 2000 |
|
|
10楼#
发布于:2004-06-09 12:26
谢谢各位!我再看看书和资料
|
|