wei_ziyong
驱动牛犊
驱动牛犊
  • 注册日期2003-12-31
  • 最后登录2010-04-30
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望16点
  • 贡献值0点
  • 好评度16点
  • 原创分0分
  • 专家分0分
阅读:2664回复:10

线程造成内存泄露?

楼主#
更多 发布于:2004-06-07 20:35
    我在WIN32 DLL中用CreateThread()函数创建了一个线程,在线程中要使用一个64kbytes的堆空间,通过传给线程。函数线程能够正确的运行,但是当退出调用线程的程序后,出现了内存泄露的情况。
    在线程中,我已经用delete函数释放了分配的64kbytes的空间,可是,他说还剩下45Bytes的空间释放,出现内存泄露,请问这个应如和解决好啊?谢谢各位拉!
snowStart
驱动老牛
驱动老牛
  • 注册日期2004-04-06
  • 最后登录2011-06-02
  • 粉丝0
  • 关注0
  • 积分95分
  • 威望19点
  • 贡献值177点
  • 好评度1点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2004-06-08 08:29
你说的不大清楚,内存什么时候,在哪申请和释放
建议:
一般使用C\C++运行期库函数_beginthreadex可以避免这种问题,
或者你用线程同步,在适当的时候释放内存,
学习,关注,交流中... [email=fengyu@163.com]Email:snowstarth@163.com[/email] [url]http://bbs.zndev.com/?a=snowStart[/url]
wowocock
VIP专家组
VIP专家组
  • 注册日期2002-04-08
  • 最后登录2016-01-09
  • 粉丝16
  • 关注2
  • 积分601分
  • 威望1651点
  • 贡献值1点
  • 好评度1227点
  • 原创分1分
  • 专家分0分
板凳#
发布于:2004-06-08 08:55
在主线程中用GETEXITCODETHREAD来监控线程,当其退出后,在主线程中释放内存.
花开了,然后又会凋零,星星是璀璨的,可那光芒也会消失。在这样 一瞬间,人降生了,笑者,哭着,战斗,伤害,喜悦,悲伤憎恶,爱。一切都只是刹那间的邂逅,而最后都要归入死亡的永眠
wei_ziyong
驱动牛犊
驱动牛犊
  • 注册日期2003-12-31
  • 最后登录2010-04-30
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望16点
  • 贡献值0点
  • 好评度16点
  • 原创分0分
  • 专家分0分
地板#
发布于:2004-06-08 12:55
    在要调用线程的主函数中分配64kBytes内存,然后,在把内存的地址传给在dll中的线程,当终止dll中线程的运行时,由dll中被调用的线程释放内存。
    我使用了CC++运行期库函数_beginthreadex还时遇到了上述的问题阿。我发现在主线程中用malloch和new来分配内存还是存在内存泄漏的情况,但是,在主线程中用 GlobalAlloc()和HeapAlloc()时能够暂时防止内存泄漏。这是怎么的一回事啊?
    使用了CC++运行期库函数_beginthreadex来创建线程,在线程中使用malloc和new函数分配内存,应该不会在产生内存泄漏才对阿!这又是怎么的一回事?
    再次,问一下使用_beginthreadex创建的线程,当调用他的主程序退出时,如果不显示的调用一些函数来终止线程的话,CC++运行期库能够自动调用_endthreadex()函数来终止线程的运行,是这样的么?
walkonthesky
驱动中牛
驱动中牛
  • 注册日期2003-11-26
  • 最后登录2012-11-06
  • 粉丝0
  • 关注0
  • 积分1分
  • 威望20点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2004-06-08 13:10
DLL导出函数尊从__declspec调用约定,按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的。所以,你不能在DLL函数中释放内存,只能在调用该函数的主程序中释放的内存,即:

谁分配,谁释放;
谁污染,谁治理。
[img]http://www.driverdevelop.com/forum/upload/walkonthesky/2004-07-08_2004-07-07_b847.gif[/img]
walkonthesky
驱动中牛
驱动中牛
  • 注册日期2003-11-26
  • 最后登录2012-11-06
  • 粉丝0
  • 关注0
  • 积分1分
  • 威望20点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2004-06-08 13:15
线程同步,WOWOCOCK的方案是可行的方案
[img]http://www.driverdevelop.com/forum/upload/walkonthesky/2004-07-08_2004-07-07_b847.gif[/img]
wei_ziyong
驱动牛犊
驱动牛犊
  • 注册日期2003-12-31
  • 最后登录2010-04-30
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望16点
  • 贡献值0点
  • 好评度16点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2004-06-08 17:03
   你的意思是不是,只要是传给DLL引出函数的指针,就只能够在只能在调用该函数的主程序中释放的指针?
   那么我这里还有个问题,我要写的那个线程要不停的调用driver中的函数,从硬件设备读数据。那个线程能够不停的从设备读数据,要把数据不停的存放到应用程序传给线程的那个缓冲区。
  如果缓冲区的由调用读数据的线程来维护、释放,当调用了创建线的函数过后,调用函数就退出了的嘛,缓冲区也就被释放了。读数据的线程就回读数据失败!这个问题你们没有什么好的注意啊?
下面有我的原代码。
wei_ziyong
驱动牛犊
驱动牛犊
  • 注册日期2003-12-31
  • 最后登录2010-04-30
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望16点
  • 贡献值0点
  • 好评度16点
  • 原创分0分
  • 专家分0分
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语句能够终止线程的运行么?他拥有的资源也能够释放么?
  
walkonthesky
驱动中牛
驱动中牛
  • 注册日期2003-11-26
  • 最后登录2012-11-06
  • 粉丝0
  • 关注0
  • 积分1分
  • 威望20点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2004-06-09 08:55
也不完全是
关键看你的调用约定
总共三种调用约定,你自己看看资料

我说过
线程同步可以解决你的问题
你自己试一下
我就不分析你的代码了
[img]http://www.driverdevelop.com/forum/upload/walkonthesky/2004-07-08_2004-07-07_b847.gif[/img]
Leonsoft
驱动小牛
驱动小牛
  • 注册日期2003-05-08
  • 最后登录2012-08-11
  • 粉丝1
  • 关注0
  • 积分21分
  • 威望281点
  • 贡献值1点
  • 好评度103点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2004-06-09 11:05
建议你去看看 Jeffer Richter那本经典名著
programming AP for windows  2000
I will do the best with what the God gave me.
wei_ziyong
驱动牛犊
驱动牛犊
  • 注册日期2003-12-31
  • 最后登录2010-04-30
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望16点
  • 贡献值0点
  • 好评度16点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2004-06-09 12:26
谢谢各位!我再看看书和资料
游客

返回顶部