【发布时间】: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