c++ - “Strange”内存泄漏-TCP网络

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

我有很多建立TCP网络的类-使用boost::asio,使用Packet进行传输。 (Packet的基类是std::vector<char>)

我以为我已经解决了所有可能的内存泄漏,但是后来我在关闭客户端之前只是关闭了服务器-这应该不会造成任何问题-且_CrtDumpMemoryLeaks报告了内存泄漏。因此,我将Visual Leaks Detector添加到了项目中,并检查了这些内存泄漏发生的位置。

void dumpMemoryLeaks(void) { CrtDumpMemoryLeaks(); }
//and in main:
atexit(dumpMemoryLeaks);

回到报告VLD内存泄漏的行,这似乎有点...对我来说很奇怪。

我有一个AsyncAcceptor类,我在构造函数的初始化程序列表new BoostSocket中分配该类-原始指针(普通和SSL套接字的包装器)。在AsyncAcceptor的析构函数中,如果原始指针有效,则将其正确删除。
_acceptor = new AsyncAcceptor(service, bindIP, port); //No memory leak for this pointer
//...
_acceptor->AsyncAcceptManaged(_OnSocketAccept); //Function pointer

AsyncAcceptManaged内部,服务器正在等待连接并传递另一个指针-一个内存泄漏。
//Set socket properties
//Call handler function passed as parameter
handler(_socket); //Raw pointer passed to handler
_socket = nullptr;
_socket = new BoostSocket(_acceptor.get_io_service()); //with ctx for SSL, if defined
//If the acceptor is not closed, it calls `AsyncAcceptManaged` again.

现在到处理程序函数。
void OnSocketOpen(BoostSocket *sock)
{
    //set additional socket options and check for error
    //Note: SocketType is template parameter of class - allowing different socket types
    std::shared_ptr<SocketType> newSocket(new SocketType(sock));
    delete sock;
    sock = nullptr;
}
SocketType始终具有一个基类,并且BoostSocket *具有相同的构造函数重载。
Socket(BoostSocket *socket)
    : _socket(std::move(*socket))
{
    //...
}

BoostSocket中,成员_socket是std::unique_ptr<SocketType>,其中SocketType是tcp::socketboost::asio::ssl::stream<tcp::socket>的typedef。
BoostSocket(BoostSocket &&s)
    : _socket(std::move(s._socket))
{ }

可视泄漏检测器指向此堆栈:
  • AsyncAcceptor::AsyncAcceptManaged
  • OnSocketOpen-处理程序
  • shared_ptr-内存(452)-explicit shared_ptr(_Ux *_Px)
  • void _Resetp(_Ux *_Px)

  • 也有微笑的“奇怪”报告。
    Packet p;
    //add data & add Packet to a std::queue
    QueuePacket(Packet &&p);
    
    //Inside QueuePacket:
    _queue.push(std::move(p));
    

    内存泄漏:
  • 队列(111)-void push(value_type&& _Val)
  • deque(1181)-void push_back(value_type&& _Val)


  • 内存泄漏(_socketstd::unique_ptr):
    BoostSocket(boost::asio::io_service &ioService)
        : _socket(new SocketType(ioService)) //<--- here
    { }
    

    内存泄漏(m_Memberstd::shared_ptr):
    m_Member = std::move(std::shared_ptr<StoredClass>(new StoredClass(shared_from_this()) ) );
    

    大量内存泄漏(_readBufferstd::vector<char>):
    _readBuffer.resize(static_cast<std::size_t>(DataUnits::DATA_UNIT_MB) * 5); //resize to 5 MB
    

    我认为最后一次内存泄漏是由于在内存泄漏报告时套接字未正确销毁而引起的。但是我无法想象问题可能出在哪里。我的原始指针已正确处理,对于其他任何事情,我都使用智能指针。

    Visual Leak Detector detected 17 memory leaks (5244907 bytes).



    这是VLD的正确报告吗? 我似乎找不到导致所有问题的内存泄漏。任何提示或解决方案表示赞赏。

    最佳答案

    如果您担心它是否可能是误报,则需要在调试器中循环运行程序的“核心逻辑”。每次以兆字节为单位,这应该很快确认内存是否泄漏。

    关于程序的实际设计:

    My raw pointers are handled properly and for anything else I use smart pointers.

    ...

    void OnSocketOpen(BoostSocket *sock)
    {
        //set additional socket options and check for error
        //Note: SocketType is template parameter of class - allowing different socket types
        std::shared_ptr<SocketType> newSocket(new SocketType(sock));
        delete sock;
        sock = nullptr;
    }
    


    该语句和我正在采样的代码似乎彼此矛盾。

    通常,对于C++ 11 / C++ 14,通常的建议是,永远不要对处理原始指针,永远不要对处理显式newdelete关键字。显然,没有规则是100%绝对可靠的(我建议您在计算机显示器上用沙皮纸写出来),但是在这种情况下,我会说99.99 ...%的时间仍然是正确的。

    因此,每次处理原始指针时,如果尚未使用std::unique_ptr(如果它拥有对象)或std::shared_ptr(如果有多个对象拥有),则可以将它们替换。我看到您已经对某些对象使用std::unique_ptrstd::shared_ptr了;确保对所有指针都执行此操作。

    其次,将每次使用new替换为适当的std::make_uniquestd::make_shared。除非您正在编写客户删除程序,否则消除对delete的所有引用;即使这样,也请确保这确实是您所需要的。

    第三,要非常注意代码的语义:
    m_Member = std::move(std::shared_ptr<StoredClass>(new StoredClass(shared_from_this()) ) );
    

    一般而言,没有理由“移动” std::shared_ptrstd::shared_ptr之所以存在,是允许指针的安全拷贝语义,并且在 Action 是适当的选择方案中,编译器通常是足够聪明来弄明白你。这段代码本身可能不错(尽管std::move是多余的),但是您可能还需要查看其他代码区域。

    我无法指出可能是罪魁祸首的任何特定代码(特别是因为我们此处没有完整的代码 list ),但是如果您解决了所有这些问题,很可能会解决内存泄漏。

    关于c++ - “Strange”内存泄漏-TCP网络,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37923384/

    相关文章:

    c++ - Qt QLabel 默认文本

    c++ - 从抽象类创建链

    c++ - 将一个对象的函数传递给另一个类的另一个 std::function

    android - 有没有办法在 Android 上安全地处理内存中的敏感数据?

    c# - Process.WorkingSet64 返回最大值 4294967295

    c++ - 在 Electron 中使用自定义 Node 包

    c++ - 如何从输入文件中查找未知数量的行和列?

    c++ - 为什么 getline() 跳过输入,即使在 cin.clear() 之后?

    c++ - 文字数字是否可变?

    memory - 为什么在使用不安全的 Rust 访问超出范围的变量时没有段错误?