C++ C++;Boost ASIO异步发送到内存泄漏

C++ C++;Boost ASIO异步发送到内存泄漏,c++,memory,memory-leaks,boost-asio,C++,Memory,Memory Leaks,Boost Asio,我目前正在使用UDP套接字客户端。我目前注意到内存泄漏,我尝试了几种方法希望能消除它,但它仍然占上风。在我的主要部分中,我有一个char*,它是malloc'd。然后我调用以下函数发送数据: void Send(const char* data, const int size) { Socket.async_send_to(boost::asio::buffer(data, size), Endpoint, boost::bind(&MulticastSender::Handle

我目前正在使用UDP套接字客户端。我目前注意到内存泄漏,我尝试了几种方法希望能消除它,但它仍然占上风。在我的主要部分中,我有一个
char*
,它是
malloc
'd。然后我调用以下函数发送数据:

void Send(const char* data, const int size) {
    Socket.async_send_to(boost::asio::buffer(data, size), Endpoint, boost::bind(&MulticastSender::HandleSendTo, this, boost::asio::placeholders::error));   
}
如果我运行此代码,它将始终泄漏内存。但是,如果我注释掉
async\u send\u to
调用,内存将保持一致。 我尝试了几种不同的方法(见下文),但它们似乎都只会加速内存泄漏

注意,在调用完成之前,传递给Send的
char*
可能会获得
免费
'd。然而,在我的变体中,我已经采取了预防措施来处理这个问题

变体1:

void Send(const char* data, const int size) {
    char* buf = (char*)malloc(size);
    memcpy(buf, data, size);
    Socket.async_send_to(boost::asio::buffer(buf, size), Endpoint, boost::bind(&MulticastSender::HandleSendTo, this, boost::asio::placeholders::error, buf));   
}

void HandleSendTo(const boost::system::error_code& ec, const char* buf) {
    free(buf);
}
class MulticastSender {
    char* Buffer;

    public:
    void Send(const char* data, const int size) {
        Buffer = (char*)malloc(size);
        memcpy(Buffer, data, size);
        Socket.async_send_to(boost::asio::buffer(Buffer, size), Endpoint, boost::bind(&MulticastSender::HandleSendTo, this, boost::asio::placeholders::error));
    }

    void HandleSendTo(const boost::system::error_code& ec) {
        free(Buffer);
    }
}
变体2:

void Send(const char* data, const int size) {
    char* buf = (char*)malloc(size);
    memcpy(buf, data, size);
    Socket.async_send_to(boost::asio::buffer(buf, size), Endpoint, boost::bind(&MulticastSender::HandleSendTo, this, boost::asio::placeholders::error, buf));   
}

void HandleSendTo(const boost::system::error_code& ec, const char* buf) {
    free(buf);
}
class MulticastSender {
    char* Buffer;

    public:
    void Send(const char* data, const int size) {
        Buffer = (char*)malloc(size);
        memcpy(Buffer, data, size);
        Socket.async_send_to(boost::asio::buffer(Buffer, size), Endpoint, boost::bind(&MulticastSender::HandleSendTo, this, boost::asio::placeholders::error));
    }

    void HandleSendTo(const boost::system::error_code& ec) {
        free(Buffer);
    }
}
然而,这两种变化似乎只会加速内存泄漏。我也尝试过删除
async\u send\u to
,只调用
boost::asio::buffer(data,size)
,但正如在其他问题中所解释的,缓冲区并不拥有内存,因此由用户安全地管理它。有没有想过是什么导致了这个问题以及如何解决它

编辑1:

void Send(const char* data, const int size) {
    char* buf = (char*)malloc(size);
    memcpy(buf, data, size);
    Socket.async_send_to(boost::asio::buffer(buf, size), Endpoint, boost::bind(&MulticastSender::HandleSendTo, this, boost::asio::placeholders::error, buf));   
}

void HandleSendTo(const boost::system::error_code& ec, const char* buf) {
    free(buf);
}
class MulticastSender {
    char* Buffer;

    public:
    void Send(const char* data, const int size) {
        Buffer = (char*)malloc(size);
        memcpy(Buffer, data, size);
        Socket.async_send_to(boost::asio::buffer(Buffer, size), Endpoint, boost::bind(&MulticastSender::HandleSendTo, this, boost::asio::placeholders::error));
    }

    void HandleSendTo(const boost::system::error_code& ec) {
        free(Buffer);
    }
}
正如在评论中所建议的,我已经预先分配了一个缓冲区(用于测试目的),并且我从未解除分配它,但是,内存泄漏仍然存在

class MulticastSender {
    char* Buffer;
    const int MaxSize = 16384;

    public:
    MulticastSender() {
        Buffer = (char*)malloc(MaxSize);
    }

    void Send(const char* data, const int size) {
        memcpy(Buffer, data, size);
        Socket.async_send_to(boost::asio::buffer(Buffer, size), Endpoint, boost::bind(&MulticastSender::HandleSendTo, this, boost::asio::placeholders::error));
    }

    void HandleSendTo(const boost::system::error_code& ec) {

    }
}
编辑2: 根据要求,这里是问题的MCVE。在此过程中,我还观察到一个有趣的行为,我将在下面解释

#include <string>
#include <iostream>
#include <functional>
#include <thread>

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

class MulticastSender {
private:
    boost::asio::io_service IOService;
    const unsigned short Port;
    const boost::asio::ip::address Address;
    boost::asio::ip::udp::endpoint Endpoint;
    boost::asio::ip::udp::socket Socket;
    boost::asio::streambuf Buffer;

    void HandleSendTo(const boost::system::error_code& ec) {
        if(ec) {
            std::cerr << "Error writing data to socket: " << ec.message() << '\n';
        }
    }

    void Run() {
        IOService.run();
    }

public:
    MulticastSender(const std::string& address,
                    const std::string& multicastaddress,
                    const unsigned short port) : Address(boost::asio::ip::address::from_string(address)),
                                                 Port(port),
                                                 Endpoint(Address, port),
                                                 Socket(IOService, Endpoint.protocol()) {
        std::thread runthread(&MulticastSender::Run, this);
        runthread.detach();
    }

    void Send(const char* data, const int size) {
        std::ostreambuf_iterator<char> out(&Buffer);
        std::copy(data, data + size, out);
        Socket.async_send_to(Buffer.data(), Endpoint, boost::bind(&MulticastSender::HandleSendTo, this, boost::asio::placeholders::error));
    }
};

const int SIZE = 8192;

int main() {
    MulticastSender sender("127.0.0.1", "239.255.0.0", 30000);
    while(true) {
        char* data = (char*)malloc(SIZE);
        std::memset(data, 0, SIZE);
        sender.Send(data, SIZE);
        usleep(250);
        free(data);
    }
}
#包括
#包括
#包括
#包括
#包括
#包括
类多播发送器{
私人:
boost::asio::io_服务IOService;
const无符号短端口;
常量boost::asio::ip::地址;
boost::asio::ip::udp::endpoint;
boost::asio::ip::udp::socket;
boost::asio::streambuf缓冲区;
void HandleSendTo(const boost::system::error_code&ec){
国际单项体育联合会(欧共体){

std::cerr类变体看起来更好,您可以使用
boost::asio::streambuf
作为网络io的缓冲区(它不会泄漏,也不需要太多维护)

//发送函数
无效的
发送(字符常量*数据,大小)
{
std::ostreambuf_迭代器输出(&buffer_);
标准::复制(数据,数据+大小,输出);
socket.async\u send\u to(缓冲区、端点、,
std::绑定和多播\u发送方,
这个,std::占位符::1));
}
在类内移动套接字和端点是一个好主意。此外,您应该记住,当对象超出范围时,异步操作可能会完成。我建议使用
从\u this启用\u shared\u(boost或std flavors)并从\u this()传递
shared\u
而不是
将此
绑定到绑定函数。 整个解决方案如下所示:

#包括
类多播发送程序:
public std::从此\u启用\u共享\u{
使用boost::asio::ip::udp;
udp::套接字;
udp::端点;
boost::asio::streambuf缓冲区;
公众:
多播发送程序(boost::asio::io\ U服务和io\ U服务,短端口,
udp::端点常量和远程):
套接字(io_服务,udp::端点(udp::v4(),端口)),
端点(远程)
{
}
无效的
发送(字符常量*数据,大小)
{
std::ostreambuf_迭代器输出(&buffer_);
标准::复制(数据,数据+大小,输出);
套接字异步发送到(缓冲区、端点、,
std::绑定和多播\u发送方,
共享_from_this(),std::占位符::_1));
}
无效的
handle_send(boost::system::error_code const&ec)
{
}
};
编辑 只要不需要在写处理程序中执行任何操作,就可以使用lambda(需要C++11)作为完成回调

//发送函数
无效的
发送(字符常量*数据,大小)
{
std::ostreambuf_迭代器输出(&buffer_);
标准::复制(数据,数据+大小,输出);
socket.async\u send\u to(缓冲区、端点、,
[](boost::system::error\u code const&ec){

std::cerr内存没有泄漏,因为分配的内存仍然有一个句柄。但是,会持续增长,因为:

  • io_服务
    未运行,因为没有工作,因此正在返回。这将导致分配完成处理程序,将其排入
    io_服务
    ,但既不执行也不释放。此外,预计在完成处理程序中发生的任何清理都不会发生。值得注意的是,在销毁<代码> IoService < /代码>,完成处理程序将被销毁,不被调用;因此,不能只在完成处理程序的执行过程中执行清理。关于何时<代码> IoService::/(代码)>块或块,请考虑阅读问题。
  • streambuf
    的输入序列从未被使用。主循环中的每次迭代都将附加到
    streambuf
    ,然后该循环将发送先前的消息内容和新附加的数据。有关
    streambuf
    的总体使用情况的更多详细信息,请参阅答案
其他几点:

  • 程序无法满足的要求,其中底层缓冲区内存的所有权由调用者保留,调用者必须保证它在调用处理程序之前保持有效。在这种情况下,当通过
    ostreambuf\u迭代器
    复制到
    streambuf
    时,
    streambuf
    的输入序列被修改使从返回的缓冲区无效
  • 在关机期间,需要对运行
    io\u服务的线程执行某种形式的同步。否则,可能会调用未定义的行为

为了解决这些问题,c