dm119 发表于 2010-7-2 16:08:15

Proactor模式下ACE_Asynch_Connector内存泄露问题

void CProactorClient::Release()
{
    if (this->handle () != ACE_INVALID_HANDLE)
    {
      this->reader_.cancel();
      this->writer_.cancel();
      ACE_OS::shutdown(this->handle_, ACE_SHUTDOWN_BOTH);
      ACE_OS::closesocket (this->handle ());
      this->handle (ACE_INVALID_HANDLE);   
      delete this;
    }
    cur_ = NULL;
}

void CProactorClient::open (ACE_HANDLE h, ACE_Message_Block&)
{

   if (this->reader_.open (*this, h) != 0 )
   {
         ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"),
             ACE_TEXT ("CProactorClient open reader_")));
      
         delete this;
         return;
   }
      if (this->writer_.open (*this) != 0 )
      {
          delete this;
          ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"),
            ACE_TEXT ("CProactorClient open write_")));
          return;
      }
   
    msgblock_ = new ACE_Message_Block(1024*10);
   if (this->reader_.read (*msgblock_, msgblock_->space ()) != 0)
   {
      ACE_TRACE("Begin read fail\n");
         return;
   }
   
    ACE_TRACE("Begin open OK \n");
    TRACE("Begin client open OK \n");
}

void CProactorClient::handle_read_stream(const ACE_Asynch_Read_Stream::Result &result)
{
    ACE_Message_Block &mb = result.message_block ();
    if (!result.success () || result.bytes_transferred () == 0)
    {
      
      ACE_TRACE("Client Close. \r\n");   
      TRACE("Client Close. \r\n");   
      this->Release();
      return;
    }
   
    msgblock_->reset();
   if (this->reader_.read (*msgblock_, msgblock_->space ()) != 0)
    {
      ACE_TRACE("read data failed!");
      TRACE("read data failed!\r\n");
    }
}

void CProactorClient::handle_write_stream(const ACE_Asynch_Write_Stream::Result &result)
{
    ACE_Message_Block &mb = result.message_block ();
    mb.release();
}

int CProactorClient::WriteDate(char *szSendBuf, int nSendCnt)
{

    ACE_Message_Block *smb = new ACE_Message_Block(nSendCnt+1);
    smb->copy(szSendBuf, nSendCnt);
    int nResult = this->writer_.write(*smb, smb->length());
   
   return nResult;
}

Windows XP+VS2008,非常简单的客户端连接处理类,拷贝例子修改下的。

连接服务器时调用:

    ACE_Asynch_Connector<CProactorClient> m_curConnector;
    ACE_INET_Addr addr(m_nConnectPort, (char*)(LPCSTR)m_strSvrIPAddr);      
    m_curConnector.open();
    m_curConnector.connect(addr);

每次连接成功后,通过任务管理器可以发现内存增长了,但是连接断开后,内存没有减下来,
通过跟踪调试,发现connect()里面会new 不少东西,据说这些东西在完成回调后会释放的,
但是搞不懂在哪里释放。另外可以确认,连接断开的时候delete this被调用。


大虾们出来指点下,看看哪里写出了什么,或者是还需要调用什么来释放连接时产生的内存。

PS: 做过测试,只连接不做任何数据的收发操作,同样会存在内存增长,所以可以确认连接的时候
ACE里面new的内存在delete this之后还是没有被释放的。

winston 发表于 2010-7-2 17:28:36

用工具查比较理想。
使用boundschecker或者purify.

freeeyes 发表于 2010-7-2 18:26:42

泄露似乎是你的Message_block没有释放。
if (!result.success () || result.bytes_transferred () == 0)
    {
      
      ACE_TRACE("Client Close. \r\n");   
      TRACE("Client Close. \r\n");   
      this->Release();    <-这里你的mb没有release()
      return;
    }

多看看ACE的Test例子,有助于学习。

dm119 发表于 2010-7-3 10:37:32

接受数据只使用一个msgblock_,这个在析构函数中已经释放,不是该变量的问题。

freeeyes 发表于 2010-7-5 10:28:51

你把
    msgblock_ = new ACE_Message_Block(1024*10);
   if (this->reader_.read (*msgblock_, msgblock_->space ()) != 0)
   {
      ACE_TRACE("Begin read fail\n");
         return;
   }
注释掉,再看内存有无泄漏。若没有就可以基本肯定在handle_read_stream()函数里面的问题。
1.mb->release();未必会释放你的内存,这要看你的Message_block引用计数器的数值。
2.Proactor是异步模式,可能会并行调用你的handle_read_stream(),这里要注意你的内存指针。
页: [1]
查看完整版本: Proactor模式下ACE_Asynch_Connector内存泄露问题