单独线程中 TCPClient 的内存泄漏
Memory Leak with TCPClient in separate thread
我正在尝试使用以下函数从网络流中读取一些字符串数据:
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() 函数每秒从 Timer Tick 事件调用,代码如下:
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.
}
这导致了一些内存泄漏。应用程序在 运行ning 40-45 分钟后因 OutOfMemory 异常而崩溃。
我的问题是是否有适当的方法来处理新线程,因为它只会存活 1 秒?我该如何解决这个问题?
我必须 运行 在一个新线程中使用此函数,因为当在与 UI 相同的线程中时,它往往会冻结它。即使是很小的鼠标移动也需要几秒钟才能得到处理。
同样的观点,如果Tick事件在同一个线程中调用该函数,则不存在内存泄漏的问题。
private void Timer_Tick(object sender, EventArgs e)
{
readFromConnection();
//No memory leak here.
}
只需使用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
是不好的方法。简单地说,使用 while
语句来读取流。
不需要 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
我正在尝试使用以下函数从网络流中读取一些字符串数据:
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() 函数每秒从 Timer Tick 事件调用,代码如下:
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.
}
这导致了一些内存泄漏。应用程序在 运行ning 40-45 分钟后因 OutOfMemory 异常而崩溃。
我的问题是是否有适当的方法来处理新线程,因为它只会存活 1 秒?我该如何解决这个问题?
我必须 运行 在一个新线程中使用此函数,因为当在与 UI 相同的线程中时,它往往会冻结它。即使是很小的鼠标移动也需要几秒钟才能得到处理。
同样的观点,如果Tick事件在同一个线程中调用该函数,则不存在内存泄漏的问题。
private void Timer_Tick(object sender, EventArgs e)
{
readFromConnection();
//No memory leak here.
}
只需使用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
是不好的方法。简单地说,使用 while
语句来读取流。
不需要 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