1

私はソケット サーバーを持っています。新しい接続が確立されるたびに、XClient クラスがインスタンス化され、それをマップに挿入しています。タスクマネージャでメモリ使用量を見ています。たとえば、新しい接続が確立されるたびに、プログラムのメモリ使用量が 800kb 増加するとします。そのクラス内には、このクライアントがアクティブかどうかを示す接続変数があります。無限に実行してマップのすべての要素を反復処理するスレッドを作成し、接続された変数が true か false かを確認しています。false の場合、以前にインスタンス化された 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;
4

3 に答える 3

1

mapいくつかの問題がありますが、主な問題は、同期がまったく行われていないスレッド間で共有しているように見えることです。それはあらゆる種類のトラブルにつながる可能性があります。

于 2012-05-20T02:48:33.760 に答える
1

またはを使用していますc++11Boost?このようなメモリ リークの悪夢を避けるために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;
}

注:上記のコードはテストされていません。私はそれをコンパイルしようとさえしていません。

于 2012-05-20T03:08:04.120 に答える
0

VS、UNIX/Linux で消去した後、STL イテレータはどうなりますか? を参照してください。. あなたの場合、すべてを削除しているわけではないので、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++;
    }
}
于 2012-05-20T03:10:46.637 に答える