内存泄漏与TCPClient在单独的线程中

时间:2017-12-11 18:09:55

标签: c# multithreading memory-leaks tcpclient

我正在尝试使用以下函数从网络流中读取一些字符串数据:

static TcpClient client;
static NetworkStream nwStream;

private void conn_start_Click(object sender, EventArgs e)
{
   //Click on conn_start button starts all the connections

   client = new TcpClient(tcp_ip.Text, Convert.ToInt32(tcp_port.Text));
   nwStream = client.GetStream();
   readBuff="";
   Timer.Start();
}

string readBuff;
private void readFromConnection()
{
  string x1 = "";
  byte[] bytesToRead = new byte[client.ReceiveBufferSize];
  int bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize);
  x1 = Encoding.ASCII.GetString(bytesToRead, 0, bytesRead);
  //
  //some more code to format the x1 string      
  //
  readBuff = x1;

  bytesToRead = null;
  GC.Collect();
}

现在,使用以下代码从Timer Tick事件中每秒调用 readFromConnection() 函数:

private void Timer_Tick(object sender, EventArgs e)
{
   Thread rT1 = new Thread(readFromConnection);
   rT1.Start();
   //app crashes after 40-45 min, out of memory exception.
}

这会导致一些内存泄漏。运行40-45分钟后,应用程序崩溃并出现OutOfMemory异常。

我的问题是,是否有正确的方法来处理新线程,因为它只能活1秒钟?我该如何克服这个问题?

我必须在新线程中运行此函数,因为在与UI相同的线程上,它往往会冻结它。即使是小型鼠标移动也需要几秒钟才能完成处理。

从相同的角度来看,如果Tick事件在同一个线程中调用该函数,则不存在内存泄漏问题。

private void Timer_Tick(object sender, EventArgs e)
{
   readFromConnection();
   //No memory leak here.
} 

2 个答案:

答案 0 :(得分:2)

不需要Timer,您可以将Receive逻辑置于一个无限循环内,并且可以在每次迭代之间为线程添加睡眠指令。您不应该使用ReceiveBufferSize从套接字流中读取数据。 ReceiveBufferSize与另一方发送的字节数或可供我阅读的字节数不同。您可以使用Available,即使我在从网络中读取大文件时也不信任此属性。您可以使用client.Client.Receive方法,此方法将阻止调用线程。

private void readFromConnection()
{
    while (true)
    {
        if(client.Connected && client.Available > 0)
        {
            string x1 = string.Empty;
            byte[] bytesToRead = new byte[client.Available];
            int bytesRead = client.Client.Receive(bytesToRead);
            x1 = System.Text.Encoding.Default.GetString(bytesToRead);
        }
        Thread.Sleep(500);
    }
}

最后,关于GC,请查看this question

答案 1 :(得分:1)

只需使用bt内存流来防止内存泄漏。

Flush

此外,使用private void readFromConnection() { string x1 = ""; byte[] bytesToRead = new byte[client.ReceiveBufferSize]; int bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize); x1 = Encoding.ASCII.GetString(bytesToRead, 0, bytesRead); // //some more code to format the x1 string // readBuff = x1; bytesToRead = null; nwStream.Flush(); // Add this line GC.Collect(); } 和触发器Timer是不好的方法。简单地说,使用readFromConnection语句来读取流。