C# 流读取器关闭 - 内存泄漏

本文关键字:内存 泄漏 读取 | 更新日期: 2023-09-27 18:33:51

我编写了一个.NET C#Windows服务,该服务在我们的服务器上运行了很长时间(几个月)。

昨天我检查了一下,发现它使用了600MB的内存。我重新启动了该服务,现在它使用 60MB 内存。

我已经开始检查为什么它使用了这么多内存。以下函数会导致内存泄漏吗?

我认为它不见了.Close() for StreamReader.

作为测试,我已经循环运行以下函数 1000 次,我没有看到内存增加。

private static string GetTemplate(string queryparams)
{
    WebRequest request = HttpWebRequest.Create(uri);
    request.Method = WebRequestMethods.Http.Get;
    WebResponse response = request.GetResponse();
    StreamReader reader = new StreamReader(response.GetResponseStream());
    string tmp = reader.ReadToEnd();
    response.Close();
}

C# 流读取器关闭 - 内存泄漏

您的代码正在关闭响应,但不关闭读取器。

var tmp = string.Empty;
using(var reader = new StreamReader(response.GetResponseStream())
{
    tmp = reader.ReadToEnd();  
}
/// do whatever with tmp that you want here...

应释放所有实现IDisposable的对象,例如 WebResponseStreamReader

private static string GetTemplate(string queryparams)
{
    WebRequest request = HttpWebRequest.Create(uri);
    request.Method = WebRequestMethods.Http.Get;
    using(var response = request.GetResponse())
    using(var reader = new StreamReader(response.GetResponseStream())
       string tmp = reader.ReadToEnd();
}

代码不会产生内存泄漏。

正如每个人都指出的那样,代码并不理想(将导致关闭资源的时间比您预期的要晚),但是当 GC 开始运行并完成未使用的对象时,它们将被释放。

确定您看到内存泄漏还是您只是假设您有一个基于某个半随机值的内存泄漏?即使未分配任何对象,CLR 也可能无法释放托管堆使用的内存,如果没有足够的内存压力(尤其是在 x64 中),则可能不需要运行 GC

如果你想

看看内存是否会增加,我建议进行 1000 次以上的迭代。如果是内存泄漏,每次迭代只会占用一小部分内存。

我不确定这是否是内存泄漏的来源,但是当您完成StreamReader时,.Close()它们是一个很好的做法。

使用

StreamReader 时,最好使用"using",然后在对象不再在范围内时实现 IDisposable 接口。

using (var reader = new StreamReader(FilePath))
  {
    string tmp = reader.ReadToEnd();
  }

至于你的问题1000次不是很多递归。尝试离开应用程序几个小时,然后输入几万,这将为您提供更好的指示。

它可能取决于您

使用它的频率,因为您不使用esplicit调用来读取器的Dispose()。为了确保您在这些行中做了任何可能的事情,请将它们写下来,例如:

private static string GetTemplate(string queryparams)
{
    WebRequest request = HttpWebRequest.Create(uri);
    request.Method = WebRequestMethods.Http.Get;
    WebResponse response = request.GetResponse();
    using(StreamReader reader = new StreamReader(response.GetResponseStream())){
         string tmp = reader.ReadToEnd();
         response.Close();
    }
    // here will be called Dispose() of the reader 
    // automatically whenever there is an exception or not.
}