我有一个套接字服务器,每次建立新连接时,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;
答案 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++;
}
}