boost :: asio socket async_read_some操作导致内存泄漏

时间:2014-03-30 22:01:28

标签: c++ boost memory-leaks boost-asio

下面的代码有一个非常麻烦的内存泄漏,我无法确定,即使使用Valgrind。

void connect_handler(const boost::system::error_code& error)
{
  if (!error)
    std::cout << "Connected to server successfully." << std::endl;
}

void read_handler(const boost::system::error_code& error, 
                  std::size_t bytes_transferred)
{
  if (!error) {
    std::cout << "Transferred " << bytes_transferred 
              << "bytes." << std::endl;
  }
}

int main(int argc, char* argv[])
{
  try
  {
    if (argc != 3)
    {
      std::cerr << "Usage: client <host> <port>" << std::endl;
      return 1;
    }

    boost::asio::io_service io_service;

    boost::asio::ip::tcp::resolver resolver(io_service);
    boost::asio::ip::tcp::resolver::query query(argv[1], argv[2],
      boost::asio::ip::resolver_query_base::numeric_service);
    boost::asio::ip::tcp::resolver::iterator endpoint_iterator = 
      resolver.resolve(query);

    boost::asio::ip::tcp::socket socket(io_service);
    boost::asio::async_connect(socket, endpoint_iterator,
      boost::bind(&connect_handler, boost::asio::placeholders::error));
    std::string ctxt_message = "";
    std::stringstream SS2;
    // std::vector<char> message_vector;
    for (;;)
    {
      boost::array<char, 1024> buf;
      boost::system::error_code error;
      size_t len = 0;
      /* WHAT I BELIEVE TO BE THE MEAT OF THE PROBLEM: */
      socket.async_read_some(boost::asio::buffer(buf, 1024),
        boost::bind(&read_handler, boost::asio::placeholders::error,len));
      if (error == boost::asio::error::eof)
        break; // Connection closed cleanly by peer.
      else if (error)
        throw boost::system::system_error(error); // Some other error.
      SS2.write(buf.data(), len);
    }
  }
  catch (std::exception& e)
  {
    std::cerr << e.what() << std::endl;
  }

  return 0;
}

我不允许Valgrind直到最后运行该程序,因为它崩溃了我的系统,但在让它运行几秒钟并取消操作后,我得到以下信息:

==2661== HEAP SUMMARY:
==2661==     in use at exit: 1,010,029,476 bytes in 9,619,333 blocks
==2661==   total heap usage: 9,619,375 allocs, 42 frees, 1,010,034,865 bytes allocated
...
==2661== 1,010,028,180 bytes in 9,619,316 blocks are still reachable in loss record 18 of 18
==2661==    at 0x4C2A879: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2661==    by 0x402E01: main (thread_info_base.hpp:60)
==2661== 
==2661== LEAK SUMMARY:
==2661==    definitely lost: 0 bytes in 0 blocks
==2661==    indirectly lost: 0 bytes in 0 blocks
==2661==      possibly lost: 63 bytes in 2 blocks
==2661==    still reachable: 1,010,029,413 bytes in 9,619,331 blocks
==2661==         suppressed: 0 bytes in 0 blocks

有什么想法吗?

1 个答案:

答案 0 :(得分:2)

似乎你还没有完全了解Asio模型的基于actor的并发性。

从未在您的代码段中io_service实际运行。所以,是的,它可以保留待处理的任务。

如果您打算/不/执行任何发布的异步任务(?!?),您需要取消()/ reset()io_service以避免泄漏挂起的任务。

    resolver.cancel();
    socket.cancel();
    io_service.reset();

无论如何,我认为你错过了异步调用是......异步的事实。 E.g。

  boost::system::error_code error;
  size_t len = 0;
  /* WHAT I BELIEVE TO BE THE MEAT OF THE PROBLEM: */
  socket.async_read_some(boost::asio::buffer(buf, 1024),
    boost::bind(&read_handler, boost::asio::placeholders::error,len));
  if (error == boost::asio::error::eof)
    break; // Connection closed cleanly by peer.
  else if (error)
    throw boost::system::system_error(error); // Some other error.

没有任何意义,因为 没有 曾分配给error。由于您未在服务对象上调用async_read_some(或.run().poll()),.{run,poll}_one()将无法执行。

以下是您的程序稍微固定的版本:( 注意更新的代码示例以响应评论)

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/array.hpp>
#include <iostream>

struct Program
{
    boost::array<char, 1024> _buf;
    boost::asio::io_service _io_service;
    boost::asio::ip::tcp::socket _socket;
    std::stringstream _received;

    void read_handler(const boost::system::error_code& error, std::size_t bytes_transferred)
    {
        if (!error) {
            std::cout << "Transferred " << bytes_transferred << "bytes." << std::endl;
            _received.write(_buf.data(), bytes_transferred);

            _socket.async_receive(boost::asio::buffer(_buf),
                    boost::bind(&Program::read_handler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
        } else
        {
            std::cout << "End of transfer reached: " << error.message() << "\n";
            std::cout << "------------------------------------------------------------\n";
            std::cout << "Data: '" << _received.str() << "'\n";
        }
    }

    void connect_handler(const boost::system::error_code& error)
    {
        if (!error)
        {
            std::cout << "Connected to server successfully." << std::endl;

            _socket.async_receive(boost::asio::buffer(_buf),
                    boost::bind(&Program::read_handler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

            // this is synchronous, but it could be done using async_* as well:
            _socket.send(boost::asio::buffer("GET / HTTP/1.0\r\nHost: www.google.com\r\n\r\n"));
        }
    }

    Program(std::string const& host, std::string const& service)
        : _buf(), _io_service(), _socket(_io_service), _host(host), _service(service) 
    {
    }

    int run()
    {
        boost::asio::ip::tcp::resolver resolver(_io_service);
        boost::asio::ip::tcp::resolver::query query(_host, _service, boost::asio::ip::resolver_query_base::numeric_service);
        boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

        boost::asio::async_connect(_socket, endpoint_iterator, boost::bind(&Program::connect_handler, this, boost::asio::placeholders::error));
        _io_service.run();

        return 0;
    }

    std::string const _host;
    std::string const _service;
};

int main(int argc, char* argv[])
{
    try
    {
        if (argc != 3)
        {
            std::cerr << "Usage: client <host> <port>" << std::endl;
            return 1;
        }

        Program program(argv[1], argv[2]);
        return program.run();
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
}

这是使用valgrind的测试运行(注意在更新的代码示例之前输出):

sehe@desktop:/tmp$ valgrind ./test localhost 22
==14627== Memcheck, a memory error detector
==14627== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==14627== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==14627== Command: ./test localhost 22
==14627== 
Connected to server successfully.
Transferred 41bytes.
SSH-2.0-OpenSSH_6.2p2 Ubuntu-6ubuntu0.2
==14627== 
==14627== HEAP SUMMARY:
==14627==     in use at exit: 0 bytes in 0 blocks
==14627==   total heap usage: 61 allocs, 61 frees, 7,319 bytes allocated
==14627== 
==14627== All heap blocks were freed -- no leaks are possible
==14627== 
==14627== For counts of detected and suppressed errors, rerun with: -v
==14627== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
相关问题