C# System.OutOfMemmoryException in TCP Server



我有一个用C#编写的多线程TCP服务器。客户端由服务器接受,并且在连接时不会离开服务器。在大约 1300 个活动连接后,我的软件会出现 System.OutOfMemmoryException 错误。此问题是否与 32 位系统架构和 RAM 有关?我有 32 位 Windows 7 专业版和 4 GB 内存。当我的服务器上存在大约 1300 个活动连接时,我的内存使用量约为 2.1GB,CPU 使用率为 30%。

谢谢。

在进程中创建 ~1300 个线程(在 32 位操作系统下)时会抛出System.OutOfMemmoryException。问题是您正在为每个连接创建全新的线程。这是不好的做法。

相反,您应该只使用一个线程来

管理发送数据,使用同一个线程(或可能是第二个线程)来发送数据,只使用一个线程来接受连接。

接受所有客户端的线程池的代码示例:

TcpListener tcpListener = new TcpListener(IPAddress.Any, 90);
public void BeginAccept()
{
    try { tcpListener.BeginAcceptTcpClient(AcceptClient, null); }
    catch { /* Swallowing is bad */ }
}
private void AcceptClient(IAsyncResult ar)
{
    TcpClient tcpClient;
    try { tcpClient = tcpListener.EndAcceptTcpClient(ar); }
    catch { /* Swallowing is bad */ }
    finally { BeginAccept(); }
    // TODO: Add your brand new tcpClient to some sort of collection, may be.
}

一个线程接受所有客户端的代码示例:

TcpListener tcpListener = new TcpListener(IPAddress.Any, 90);
bool isListening;
public void BeginAccept()
{
    while (isListening)
    {
        TcpClient tcpClient;
        try { tcpClient = tcpListener.AcceptTcpClient(); }
        catch { /* Swallowing is bad */ }
        // TODO: Add your brand new tcpClient to some sort of collection, may be.
    }
}

您应该查看实现异步服务器套接字。
我仍然建议在不同的线程中发送响应以避免队列/TCP重新发送。
您可以使用任务,也可以将收到的消息和相关连接添加到由工作组处理它们的并发队列中。

您的计算机/操作系统不是限制因素。它可以为每个进程分配近 4GB(如果您总共使用超过 4GB,它将开始交换/写入磁盘:这比常规内存慢得多,但它仍然可以工作)。但是,C# 编译器会限制您。默认情况下,C# 编译为 32 位,这意味着每个进程只能使用大约 2GB 的内存。这就是为什么您的服务器一旦达到 2GB 就会崩溃的原因。您可以将其编译为 64 位操作系统,这将允许您使用几乎无限的内存,但您没有 64 位操作系统,因此它不会在您的机器上运行。

最好

为每个客户端连接创建一个新进程,而不是线程。您的主进程将侦听并接受连接,当建立新连接时,它应该生成一个专门用于处理与该客户端的连接的新进程。因为每个连接都有自己的进程,所以你不会再达到2GB的限制,还有更多的优点:一旦连接关闭,回收内存就会容易得多,一个连接中的任何错误都不太可能使整个程序崩溃。当然,多进程架构的编程比多线程架构的编程要困难一些,因为没有共享内存,但这是更好的方法。

最新更新