2012-05-10 125 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次是不是很多的遞歸。嘗試離開應用程序幾個小時,並計時幾十萬,這會給你一個更好的指示。