循环中的 C++ std::unique_ptr - 内存泄漏

c++ std::unique_ptr in a loop - memory leaks

提问人:Hikaru 提问时间:10/5/2023 最后编辑:Hikaru 更新时间:10/6/2023 访问量:150

问:

unique_ptr在这个循环中是否正确使用?
每次此 while 循环结束时,整体堆大小都会略有增加。当我使用 Visual Studio 的调试工具调查代码时,似乎没有释放unique_ptr对象“task”,导致内存泄漏。
我以为unique_ptr记忆会在大括号结束后释放,在这种情况下,是每个循环的结束或 try-catch 的结束大括号。是不是有什么误会?

我的环境:VisualStudio2019、MSVC、C++17

更新(2023/10/6)
  • 我更新了代码如下。
  • 试图进行最低限度的复制,但由于某种原因我无法做到。因此,此代码可以正常工作,而不会发生内存泄漏。唯一的尊重是每个类的头文件和类名。我很困惑。
  • 这是调试工具的屏幕截图。我想知道为什么这个_container_proxy[]、TaskFactory[] 和 TaskImplA[] 不断堆积。
#include <iostream>
#include <future>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
#include <ws2tcpip.h>

class MessageTask {
public:
    MessageTask() {};
    MessageTask(char*& message) {};
    virtual ~MessageTask() {};
    void execute() {
        decide_task();
        do_task();
    }
    virtual void decide_task() = 0;
    virtual void do_task() = 0;
};

class TaskImpl : public MessageTask{
private:
    char* message;
public:
    TaskImpl() {};
    TaskImpl(char*& message) { this->message = message; };
    ~TaskImpl() {};
    void decide_task() { std::cout << message << std::endl;  return; };
    void do_task() { return; };
};

class TaskFactory {
public:
    TaskFactory() {};
    ~TaskFactory() {};
    std::unique_ptr<MessageTask> create_message_task(char*& message, int& sender) {
        if (sender == 2000) {
            return std::make_unique<TaskImpl>(message);
        }
        return nullptr;
    };
};

class UdpComm {
private:
    SOCKET m_socket;
    struct sockaddr_in m_address;
    WSADATA m_wsadata;

public:
    UdpComm() {};
    ~UdpComm() {};
    struct sockaddr_in m_address_send_from;

    void initialize_receiver() {
        WSACleanup();
        int startup_result = WSAStartup(MAKEWORD(2, 0), &this->m_wsadata);
        this->m_socket = socket(AF_INET, SOCK_DGRAM, 0);
        this->m_address.sin_family = AF_INET;
        this->m_address.sin_port = htons(5001);
        this->m_address.sin_addr.S_un.S_addr = INADDR_ANY;
        int wsa_result = bind(this->m_socket, (struct sockaddr*)&this->m_address, sizeof(this->m_address));
    };

    int receive_sync(char* buffer_ptr, const size_t buffer_size, size_t& rx_size)
    {
        int sockaddr_in_size = sizeof(this->m_address_send_from);
        int receive_result = recvfrom(this->m_socket, (char*)buffer_ptr, (int)buffer_size, 0, (struct sockaddr*)&m_address_send_from, &sockaddr_in_size);
        rx_size = (size_t)receive_result;
        return 0;
    }
};

class Receiver {
public:
    int udp_receive(UdpComm& uc_rcv) {
        while (true)
        {
            try
            {
                char buffer[1024];
                char* buffer_ptr = buffer;
                size_t buffer_size = sizeof(buffer);
                size_t rx_size = 0;
                uc_rcv.receive_sync(buffer_ptr, buffer_size, rx_size);
                int port = ntohs(uc_rcv.m_address_send_from.sin_port);
                auto factory = std::make_unique<TaskFactory>();
                auto task = factory->create_message_task(buffer_ptr, port);
                task->execute();
            }
            catch (const std::exception& ex)
            {
                std::cerr << "[ERROR] " << ex.what() << std::endl;
            }
        }
    }
};

int main() {
    auto uc_rcv = std::make_unique<UdpComm>();
    uc_rcv->initialize_receiver();
    Receiver receiver;
    receiver.udp_receive(*uc_rcv);
}

我使用 Visual Studio 2019 的调试工具进行了调查,它显示堆大小增加了。另外,我在 task->execute() 中注释掉了以下过程,但仍然发生了内存泄漏。

C++ 内存泄漏 C++17 visual-studio-2019 unique-ptr

评论

4赞 David Schwartz 10/5/2023
我不确定在不知道做什么和做什么的情况下,我们该如何回答。您是否看到没有注释掉这些线的泄漏?create_message_taskexecute
4赞 Aykhan Hagverdili 10/5/2023
请提供一个最小的可重复示例
1赞 Pepijn Kramer 10/5/2023
您独特的指针在这里根本无济于事。你做一次(在程序关闭的很晚的某个地方,它被破坏了)。因此,它绝不对您的泄漏负责(因此不应成为您问题的一部分)。泄漏必须来自create_message_task。顺便说一句,我只是让工厂成为 Receiver 类的成员变量(并让它共享类的生命周期)
2赞 Jarod42 10/5/2023
“整体堆大小略有增加”没有必要发生内存泄漏,也可能发生内存碎片......
0赞 Andrej Podzimek 10/5/2023
为什么是工厂指针?工厂级(其)头安全吗?如果没有,那么就没有好处,只会在具有多个函数“运行”实例的多线程环境中伤害您。 听起来像是异步和/或多线程的东西。staticcreate_message_task()staticudp_receive

答: 暂无答案