【问题标题】:Boost asio async_write_some leaking?Boost asio async_write_some 泄漏?
【发布时间】:2017-09-26 11:40:02
【问题描述】:

我一直在搞乱一个使用 boost::asio 进行 UDP 和 SocketCAN 通信的应用程序。 今天,我发现了一些奇怪的东西——它正在泄漏内存!

所以我拿起了我值得信赖的工具包,其中包含

echo 0 $(awk '/Private/ {print "+", $2}' /proc/`pidof main`/smaps) | bc

和 Allinea DDT 一起诊断这个问题。

我最终得到的是以下 sn-p,它使用 boost::asio::posix::basic_stream_descriptor 作为它的基础:

void Can::write(struct can_frame frame) {
  stream_.async_write_some(boost::asio::buffer(&frame, sizeof(frame)),
                           boost::bind(&Can::datSend, this)
  );
}

这里,datSend 只是一个 ping 看门狗的空函数。 我也试过了

void Can::write(struct can_frame frame) {
  stream_.write_some(boost::asio::buffer(&frame, sizeof(frame)));
}

但是由于某种原因,这会产生异常(无效数据)。

这段代码的后端看起来像这样:

boost::asio::io_service ioService_;
boost::asio::posix::basic_stream_descriptor<> stream_;

Constructor() : stream_(ioService_) {
  socketDescriptor_ = socket(PF_CAN, SOCK_RAW, CAN_RAW);

  struct timeval timeout {
      .tv_sec = 5,
      .tv_usec = 0
  };

  if (setsockopt(socketDescriptor_, SOL_SOCKET, SO_RCVTIMEO,
                 reinterpret_cast<char *>(&timeout),
                 sizeof(timeout)) < 0) {
    throw std::string("Error setting CAN socket timeout");
  }

  strcpy(interfaceRequest_.ifr_name, interfaceName.c_str());
  ioctl(socketDescriptor_, SIOCGIFINDEX, &interfaceRequest_);
  socketAddress_.can_family = AF_CAN;
  socketAddress_.can_ifindex = interfaceRequest_.ifr_ifindex;
  stream_.assign(socketDescriptor_);

  if (bind(socketDescriptor_, (struct sockaddr *)&socketAddress_,
           sizeof(socketAddress_)) < 0) {
    throw std::string("Error in socket bind");
  }

}

之后我只运行 ioservice 就是这样:

void Can::iosThreadWorker() { ioService_.run(); }

我已经阅读了很多 stackoverflow 主题以及 boost 文档,但似乎无法找到为什么这个函数会泄漏内存。

增强版 - 1.60 G++ - 6.30 操作系统:Ubuntu 17.04

【问题讨论】:

  • 您首先应该怀疑的应该是您自己的代码,而不是一个知名且大量使用的库的代码。您认为 datSend() 无关紧要,但这可能确实是泄漏发生的地方。请同时提供该函数的代码。
  • 它实际上是一个空函数:void Can::datSend(){} 我曾经记录过这个场合,但目前它只是充当占位符。
  • 你可以在你的主文件中设置一个调试钩子,一旦进入可疑函数,在任何内存分配上设置一个断点。看看他们中的任何一个是否脱颖而出
  • 我之前保存了这个内存调试器堆栈跟踪,似乎在 asio 内部,这是经常被调用的函数: boost::asio::asio_handler_allocate(unsigned long, ...) ( handler_alloc_hook.ipp) ,大约数百万次,并且永远不会被释放。
  • 事实证明这不是问题所在。从技术上讲,这甚至不是泄漏,而只是按预期连续分配内存。

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


【解决方案1】:

所以我挖得更深了,发现了这个关于 boost.io_service 的花絮:

io_service.run() 如果没有工作要做,则完成 - 因此通过运行它然后发送更多要完成的异步工作,工作没有完成。

这源于一个问题,其中有人翻转了 ioservice.run() 和异步读取回调分配以使代码看起来更好 - 现在在运行之前没有堆积工作,ioservice 可以完成它的工作并返回。

【讨论】:

  • 感谢解决它。下次,使用其他信息编辑问题,以便人们注意到(在您发布此答案之前我没有找到您的评论)
猜你喜欢
  • 2016-12-26
  • 2014-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-22
  • 1970-01-01
相关资源
最近更新 更多