繁体   English   中英

boost :: asio受体避免内存泄漏

[英]boost::asio acceptor avoid memory leak

使用boost :: asio我使用async_accept接受连接。 这很好,但是有一个问题,我需要一个如何处理的建议。 使用典型的async_accept:

  Listener::Listener(int port)
        : acceptor(io, ip::tcp::endpoint(ip::tcp::v4(), port))
        , socket(io) {
          start_accept();
  }

  void Listener::start_accept() {
      Request *r = new Request(io);
      acceptor.async_accept(r->socket(), 
        boost::bind(&Listener::handle_accept, this, r, placeholders::error));
  }

工作正常,但是存在一个问题: 请求对象是用普通的new创建的,因此它可以存储“泄漏”。 并不是真正的泄漏,它仅在程序停止时泄漏,但是我想让valgrind开心。

当然有一个选择:我可以将它替换为shared_ptr ,并将其传递给每个事件处理程序。 这将一直工作到程序停止为止,当asio io_service停止时,所有对象将被销毁,并且Request将被释放。 但是这样,我始终必须为Request拥有一个活动的asio事件,否则它将被销毁! 我认为这是直接导致崩溃的方式,所以我也不喜欢这种变体。

UPD第三个变体: Listener保存到活动连接的shared_ptr列表。 看起来不错,我更喜欢使用它,除非找到更好的方法。 缺点是:由于此架构允许对空闲连接进行“垃圾回收”,因此不安全:从侦听器中删除连接指针将立即销毁它,当某些连接的处理程序在其他线程中处于活动状态时,这可能导致segfault。 在这种情况下,使用互斥锁无法解决此问题,我们必须锁定几乎所有东西。

有没有一种使接收器与连接管理一起使用的方法, 美观又安全? 我很高兴听到任何建议。

使用此库时,避免内存泄漏的典型方法是使用shared_ptrio_service 文档专门提到了这一点

备注

上述销毁序列使程序可以使用shared_ptr<>简化其资源管理。 如果对象的生存期与连接的生存期(或其他一些异步操作序列)相关联,则该对象的shared_pt r将绑定到与该对象关联的所有异步操作的处理程序中。 其工作原理如下:

当单个连接结束时,所有关联的异步操作都将完成。 相应的处理程序对象将被销毁,并且所有对对象的shared_ptr引用都将被销毁。 要关闭整个程序,将io_service函数stop()来尽快终止所有run()调用。 上面定义的io_service析构函数会销毁所有处理程序,从而导致销毁对所有连接对象的所有shared_ptr引用。

对于您的方案,更改您的Listener::handle_accept( )方法以使用boost::shared_ptr<Request>参数。 您的第二个顾虑

从侦听器中删除连接指针将立即销毁它,当某些连接的处理程序在其他线程中处于活动状态时,这可能导致段错误。 在这种情况下,使用互斥锁无法解决此问题,我们必须锁定几乎所有东西。

通过继承类中的boost::enable_shared_from_this模板可以缓解此问题:

class Listener : public boost::enable_shared_from_this<Listener>
{
   ...
};

然后,在分派处理程序时,在绑定到Listener成员函数时,请使用shared_from_this()代替this

如果有人感兴趣,我找到了另一种方法。 Listener保存到活动连接的shared_ptr列表。 连接的结束/终止是通过io_service::post ,该调用调用被asio::strand包装的Listener::FinishConnection 通常,我总是将Request的方法包装在strand上-在DDOS和/或线程安全方面更安全。 因此,使用strandpost调用FinishConnection可以防止其他线程出现segfault

不确定这是否与您的问题直接相关,但是通过使用Boost Asio库,尤其是您提到的同一acceptor对象,我也遇到了类似的内存泄漏。 原来我没有正确关闭服务; 一些连接将保持打开状态,并且其相应对象将不会从内存中释放。 调用以下方法摆脱了Valgrind报告的泄漏:

acceptor.close();

希望这对某人有用!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM