我已经编写了一个小测试tcp监听器。所述侦听器侦听端口28328并且工作得非常好,期望客户端每次连接时都会发生巨大的资源/内存泄漏。
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
SOCKET Socket = INVALID_SOCKET;
bool TestServer()
{
WSADATA wsaData = { 0 };
if (WSAStartup(MAKEWORD(2, 2), &wsaData))
return false;
sockaddr_in addr = { 0 };
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int Enable = 1;
setsockopt(Socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&Enable, sizeof(int));
addr.sin_family = AF_INET;
addr.sin_port = htons(28328);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(Socket, (sockaddr*)&addr, sizeof(sockaddr)))
return false;
if (listen(Socket, 50))
return false;
return true;
}
void Dolisten()
{
if (TestServer())
{
sockaddr_in addr = { 0 };
SOCKET Client_Socket = 0;
int Lenght = sizeof(addr);
for (;;)
{
Client_Socket = INVALID_SOCKET;
Client_Socket = accept(Socket, (struct sockaddr *)&addr, &Lenght);
if (Client_Socket == INVALID_SOCKET)
continue;
printf("Client Connected %X\n", Client_Socket);
shutdown(Client_Socket, 2);
closesocket(Client_Socket);
}
}
}
int main(int argc, char* argv[])
{
Dolisten();
WSACleanup();
return 0;
}
虽然最初的听众比这个大得多,但可能还有很多我尚未解决的问题,现在这是我最大的问题。
我认为问题是由于接受套接字并且没有正确关闭然后泄漏到句柄泄漏而发生的。我的基础是,当我查看任务管理器和监视进程的其他工具时,我可以看到句柄数量的增加与我的连接发生的速率相同。
注意:
1)从外观来看,泄漏发生在非分页记忆中。
2)如果在linux环境中编译和使用相同的代码片段,则不会产生相同的内存/资源泄漏。
3)我已在多台Windows机器上编译并测试了此代码,并出现同样的问题。
4)(编辑)我确实看到有几个人在一些MSDN论坛和VS论坛上发布了这个确切的问题但他们被告知要做的就是提交一张票。
答案 0 :(得分:0)
非分页池是内核资源,与操作系统无法分页的内存有关,是一种稀缺资源。因此,留意它是一件好事。
它在内核中的事实意味着内存不是直接在你的控件中。可能是内存与未发送,未处理的数据包有关,在这种情况下,资源是您的程序间接负责的。
检查手柄是否泄漏 - 来自何处。 Application Verifier Microsoft : Application Verifier download可以帮助识别泄漏内存和句柄的调用堆栈。
答案 1 :(得分:0)
您所显示的应用程序中没有内存泄漏。
由于TCP / IP的工作方式,无法立即释放与已关闭连接关联的资源。在连接关闭后,数据包可能无序到达或重新传输。因此,即使在调用closesocket
之后,实际的OS套接字仍保持打开一段预定义的时间(通常为2-3分钟,可以使用TcpTimedWaitDelay进行调整)。
如果您运行netstat -an
,您将在CLOSE_WAIT或TIME_WAIT状态中看到一堆连接:
TCP 127.0.0.1:28328 127.0.0.1:56508 TIME_WAIT
TCP 127.0.0.1:28328 127.0.0.1:56510 TIME_WAIT
TCP 127.0.0.1:28328 127.0.0.1:56512 TIME_WAIT
TCP 127.0.0.1:28328 127.0.0.1:56514 TIME_WAIT
TCP 127.0.0.1:28328 127.0.0.1:56516 TIME_WAIT
. . .
当然(内核)内存需要存储这些临时状态。
此外,短暂范围内的TCP端口号不能立即重复使用,这意味着可以打开/关闭连接的 rate 非常有限。