C# TCPClient位于单独线程中的内存泄漏

C# TCPClient位于单独线程中的内存泄漏,c#,multithreading,memory-leaks,tcpclient,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

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

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();
}
现在,从计时器滴答声事件中每秒调用一次函数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.
} 
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();
}

只需使用
Flush
内存流即可防止内存泄漏

private void Timer_Tick(object sender, EventArgs e)
{
   readFromConnection();
   //No memory leak here.
} 
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();
}

另外,使用
定时器
和触发器
读取连接
是一种不好的方法。简单地说,使用
while
语句读取流

只需使用
刷新
内存流即可防止内存泄漏

private void Timer_Tick(object sender, EventArgs e)
{
   readFromConnection();
   //No memory leak here.
} 
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();
}

另外,使用
定时器
和触发器
读取连接
是一种不好的方法。简单地说,使用
while
语句读取流

不需要
计时器
,您可以将
接收
逻辑放入一个无限while循环中,并且可以在每次迭代之间为线程添加睡眠指令。您不应该使用
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
看一下不需要
计时器
,您可以将
接收
逻辑放在一个无限while循环中,并且可以在每次迭代之间为线程添加睡眠指令。您不应该使用
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
看一看

我有几个问题要问你,你为什么要手动调用
GC.Collect()
?为什么要在
Timer
Tick事件中创建线程呢?我添加了GC来检查它是否解决了任何内存泄漏问题。起初它不在那里。对于新线程,这样做是为了防止主UI冻结。请告诉我这样做是否不好?您不应该手动调用
GC.Collect()
,垃圾收集是为您管理的。您可以通过将逻辑封装在无限while循环中,并在每次迭代之间添加一条睡眠指令来摆脱计时器,这样,您只会得到一个线程。我将简短地添加一个答案。我有几个问题要问您,为什么要手动调用
GC.Collect()
?为什么要在
Timer
Tick事件中创建线程呢?我添加了GC来检查它是否解决了任何内存泄漏问题。起初它不在那里。对于新线程,这样做是为了防止主UI冻结。请告诉我这样做是否不好?您不应该手动调用
GC.Collect()
,垃圾收集是为您管理的。通过将逻辑封装在无限while循环中,并在每次迭代之间添加一条睡眠指令,您可以摆脱计时器。这样,您只会得到一个线程。我将简短地添加一个答案刷新没有对内存泄漏进行任何更改,但更改方法的建议有所帮助。谢谢刷新没有对内存泄漏进行任何更改,但更改方法的建议起到了帮助。谢谢谢谢你的改进。他们都做得很好@chiro3110很高兴我帮了你@马哈茂德非常感谢。它解决了我一周的挣扎。谢谢你的改进。他们都做得很好@chiro3110很高兴我帮了你@马哈茂德非常感谢。它解决了我一周的挣扎。