2012-05-10 126 views
1

我编写了一个很长时间(几个月)在我们的服务器上运行的.NET C#windows服务。C#StreamReader关闭 - 内存泄漏?

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

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

我认为它丢失.Close()为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(); 
} 

回答

2

该代码不会产生内存泄漏。

代码并不理想,因为每个人都指出(会导致晚于预期的关闭资源),但当GC开始运行并最终确定未使用的对象时,它们将被释放。

你确定你看到内存泄漏或者你只是假设你有一个基于一些半随机值?即使没有分配任何对象,CLR也不会释放托管堆使用的内存,如果没有足够的内存压力(特别是在x64中),GC可能不需要运行。

+0

不知道有关内存泄漏,我只是看到任务管理器中使用600MB内存(我总共只有4GB)的服务,它对我来说没有任何意义。 – RuSh

+0

无论如何修复你的代码:)。要确认它是否泄漏 - 最好使用.Net的内存分析器(搜索 - 大量信息),但是您可以通过向GC.Collect添加调用足以进行调查并查看内存使用量增长是否始终稳定在一定的价值。确保你知道如何重现病情 - 否则你会如何知道行为是否改变。 –

+0

阿列克谢,是否有什么特别的StreamReader等,可以不会导致内存泄漏没有处置?如果应用程序退出,当然,整个过程将随着所分配的资源一起被杀死。但是,在长时间无限期运行的服务中,这可能是一个真正的问题。我错过了什么吗? –

3

您的代码正在关闭响应,但不是读者。

var tmp = string.Empty; 

using(var reader = new StreamReader(response.GetResponseStream()) 
{ 
    tmp = reader.ReadToEnd(); 
} 

/// do whatever with tmp that you want here... 
0

它可能潜在地取决于您使用它的频率,因为您不使用Reader的Dispose()的esplicit调用。要确保你做什么,你可以在这行,把它们写下来,如:

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. 
} 
+0

ResponseStream和Response如何?两者都实施IDisposable并应予以处置。因此,您的代码缺少2个使用语句。 – spender

+0

我明白我错过了关于读者的一个接近:)。最大的问题是,这可能会导致600MB的内存使用率? – RuSh

3

实现IDisposableWebResponseStreamReader应配置中的所有对象。

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(); 
} 
+0

流也实现IDisposable。 – spender

+0

@spender处置StreamReader将关闭(并处置)基础流。 – Magnus

+1

同意。但是,通常我也会将其纳入,以防我后来决定转而采用另一种阅读方式,而不是隐含处置。 – spender

2

如果你想看看内存是否会增加,我会建议1000多次迭代。如果是内存泄漏,每次迭代只占用一小部分内存。

我不确定这是否是您的内存泄漏的根源,但是当您完成对它们的读取时,它是您的StreamReaders的良好实践。

1

使用StreamReader最好使用'using',那么当对象不在作用域中时,将实现IDisposable接口。

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

至于你的问题1000次是不是很多的递归。尝试离开应用程序几个小时,并计时几十万,这会给你一个更好的指示。