内存泄漏与套接字和映射

时间:2012-05-20 02:39:04

标签: c++ sockets memory map memory-leaks

我有一个套接字服务器,每次建立新连接时,XClient类都会被实例化,我将它插入到地图中。我正在通过任务管理器观察内存使用情况。每次建立新连接时,假设我的程序的内存使用量增加了800kb。在该类中,有一个连接变量,它将告诉我该客户端是否处于活动状态。我创建了一个无休止地运行的线程并遍历我的映射的所有元素,我正在检查连接变量是真还是假。如果它是假的,我(至少我认为我...)释放先前实例化的XClient类使用的内存。但是,内存使用量仅减少了800kb的一半(例如,没有精确值)。因此,当客户连接时:+ 800kb。当客户端断开连接时:-400kb。我想我有内存泄漏?如果我连接了100个客户端,那么400kb没有被释放会变成4000kb的未使用(?)内存,这将是一个问题。

所以,这是我的代码。 迭代所有元素的线程:

DWORD Update(XSockets *sockets)
{
while(true)
{
    for(sockets->it = sockets->clients.begin(); sockets->it != sockets->clients.end(); sockets->it++)
    {
        int key = (*sockets->it).first;
        if(sockets->clients[key]->connected == false) // remove the client, releasing memory
        {
            delete sockets->clients[key];
        }
    }
    Sleep(100);
}
return true;
}

将新XClients实例添加到我的地图的代码:

bool XSockets::AcceptConnections()
{
struct sockaddr_in from;

while(true)
{
    try
    {
        int fromLen = sizeof(from);
        SOCKET client = accept(this->loginSocket,(struct sockaddr*)&from,&fromLen);
        if(client != INVALID_SOCKET)
        {
            srand(time(NULL));
            int clientKey = rand();
            XClient* clientClass = new XClient(inet_ntoa(from.sin_addr),clientKey,client);
            this->clients.insert(make_pair(clientKey,clientClass));
        }
        Sleep(100);
    }
    catch(...)
    {
        printf("error accepting incoming connection!\r\n");
        break;
    }
}

closesocket(this->loginSocket);
WSACleanup();

return true;
}

声明:

    map<int,XClient*> clients;
map<int,XClient*>::iterator it;

3 个答案:

答案 0 :(得分:1)

你遇到了几个问题,但主要问题是你似乎在线程之间共享map而没有任何同步。这可能会导致各种麻烦。

答案 1 :(得分:1)

您使用的是c++11还是Boost?为了避免像这样的内存泄漏噩梦,你可以创建一个map共享指针。这样,您就可以让结构自行清理。

我就是这样做的:

#include <memory>
#include <map>
#include <algorithm>
#include <functional>
#include <mutex>

typedef std::shared_ptr<XClient> XClientPtr;
std::map<int, XClientPtr> client;
std::mutex the_lock;

bool XSockets::AcceptConnections()
{
/* snip */

    auto clientClass = std::make_shared<XClient>(/*... params ...*/);
    the_lock.lock();
    clients[clientKey] = clientClass;
    the_lock.unlock();
/* snip */
}

bool client_is_connected(const std::pair<int, XClientPtr> &p) {
    return p.second->connected;
}

DWORD Update(XSockets *sockets) {
    while(true) { /* You should probably have some kind of
                     exit condition here. Like a global "running" bool
                     so that the thread will eventually stop. */
        the_lock.lock();

        auto it = sockets->clients.begin(), end = sockets->clients.end();
        for(; it != end; ) {
            if (!it->second->connected)
                //Clients will be destructed here if their refcount goes to 0
                sockets->clients.erase(it++); 
            else
                ++it;
        }
        the_lock.unlock();
        Sleep(100);
    }
    return 1;
}

注意:以上代码未经测试。我甚至没有尝试编译它。

答案 2 :(得分:0)

What happens to an STL iterator after erasing it in VS, UNIX/Linux?。在您的情况下,您没有删除所有内容,因此您不希望使用for循环。

sockets->it = sockets->clients.begin();
while (sockets->it != sockets->clients.end())
{
    int key = (*sockets->it).first;
    if(sockets->clients[key]->connected == false) // remove the client, releasing memory
    {
        delete sockets->clients[key];
        sockets->clients.erase(sockets->it++);
    }
    else
    {
        sockets->it++;
    }
}
相关问题