线程在完成执行后没有被清理

时间:2014-04-15 09:11:47

标签: c# multithreading asynchronous tcplistener

简单实现异步多线程TCP服务器。 按预期工作,除了内存使用量持续上升。 调查后我发现那个内存都是没有被清理的线程对象。 但是,线程会写入" host disconnected"到日志文件,因为那是该线程执行的最后一行代码,我希望它能够自行清理。但这似乎并没有发生。对于每个建立的连接,创建一个线程并停止运行,但它永远不会完全清理。

发生了什么事?

也没有生成例外。

    private void AcceptNextClient()
    {
        if (acceptConnections) serverSocket.BeginAcceptTcpClient(new AsyncCallback(AcceptTcpClientCallback), serverSocket);
    }


    private void AcceptTcpClientCallback(IAsyncResult ar)
    {
        try
        {
            TcpListener serverSocket = (TcpListener)ar.AsyncState;
            TcpClient clientConnection = serverSocket.EndAcceptTcpClient(ar);
            new Thread(unused => HandleClientCommunication(clientConnection)).Start();
        }
        catch (Exception ex) { Disk.AppendLog(ex.ToString()); }
        AcceptNextClient();
    }

    private void HandleClientCommunication(TcpClient tcpClient)
    {
        string hostName = "";
        try
        {
            using (StreamWriter sw = new StreamWriter(tcpClient.GetStream()))
            using (StreamReader sr = new StreamReader(tcpClient.GetStream()))
            {
                hostName = Dns.GetHostEntry(((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address).HostName;
                bool read = true;
                while (read)
                {
                    string buffer = sr.ReadLine();
                    if (buffer == null) read = false;
                    else
                    {
                        if (buffer.ToUpper().Equals("CLOSE_CONNECTION")) read = false;
                        else
                        {
                            sw.WriteLine(buffer);
                            sw.Flush();
                        }
                    }
                }
                tcpClient.Close();
            }
        }
        catch (Exception ex)
        {
            Disk.AppendLog(hostName + " " + ex.ToString());
        }
        Disk.AppendLog("host disconnected");
    }

    public static void AppendLog(string msg)
    {
        File.AppendAllText(exePath + "errors.log", DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString() + " " +  msg + Environment.NewLine);
    }

2 个答案:

答案 0 :(得分:0)

我猜这里是你使用像这样的线程

new Thread(unused => HandleClientCommunication(clientConnection)).Start(); 
        }

如果你让我们假设每秒100次调用你最终会在你的应用程序中增加100 MB,因为每个线程需要1MB至少记住垃圾收集器不能保证即使线程也会一直收集内存已完成执行。
我在这里建议的是切换所有代码以使用任务 你的代码看起来像这样

Task.Factory.StartNew(unused => HandleClientCommunication(clientConnection)); 
        }

这就是为什么你应该使用任务而不是线程(当它可能时)

  • 创建和销毁线程是一项昂贵的操作 时间
  • 拥有大量线程会浪费内存资源并且还会损害性能 操作系统必须在可运行线程之间进行调度和上下文切换
  • 任务在线程池上安排。具体的线程数取决于所使用的调度程序。如果您的应用程序发出许多线程池请求,则线程池将尝试为所有线程池提供服务。 使用这一个线程的请求。但是,如果您的应用程序正在排队多个请求 比线程池线程可以处理它们更快,将创建其他线程。

答案 1 :(得分:0)

所以我发现答案后,注意到垃圾收集器在程序作为服务运行时无法运行,但在作为表单运行时运行(并解决所有内存问题)。

删除Main(string [] args)中的[STAThread]修复了所有问题。代码本身没有任何问题。

http://support.microsoft.com/kb/828988