2012-01-02 69 views
0

我有一個從套接字連接接收數據,儘快對HD..The數據transformate的數據並將其存儲,因爲一個複雜的算法事實上,我不希望處理速度減慢是通過使用不同的線程來存儲的。數據存儲算法類似於這種結構。它基本上將XML保存在磁盤上。爲什麼內存沒有在C#在磁盤上寫入文件後釋放

Begin Thread 
beginthread: 

XmlTextWriter xmltextWriter; 
Save Xml file 1 
xmltextWrite.close(); 

XmlTextWriter xmltextWriter; 
Save Xml file 2 
xmltextWrite.close(); 

goto beginthread: 
End Thread 

它工作正常,但如果我進去一看任務管理器,我能注意到的內存我的程序所消耗的量隨時間快速encreases(工作1小時後500MB)。這可能是合理的,因爲這個線程不如進入的數據那麼快,而且.NET框架爲我暫時存儲所有內存。但我不明白的是,爲什麼如果傳入的套接字連接將停止,即使線程繼續工作幾分鐘後,任務管理器仍會顯示500Mb的內存。爲什麼內存不會被釋放? XmlTextWriter對象是一個局部變量,並且每次都關閉。

按照要求..這是代碼

 beginthread: 
     if (sleeptime < 1000) sleeptime += 2; 

     try 
     { 

      while (hashBeginConn.Count > 0) 
      { 
       sleeptime = 0; 

       int connToApply = hashBeginConn[0]; 

       if (olddate.ToShortDateString() != ListsockConnections[connToApply].beginDate.ToShortDateString()) 
       { 
        JoinDataFromTempFile(ListsockConnections[connToApply].beginDate.Date.Subtract(olddate.Date).Days, false, d); 
        olddate = ListsockConnections[connToApply].beginDate.Date; 
       } 

       if (tocreate) 
       { 
        // XML Serialization 
        XmlTextWriter xmltextWriter; 

        Encoding enc = null; 
        if (ListsockConnections[connToApply].ENCfromCode) enc = Encoding.GetEncoding(ListsockConnections[connToApply].codepage); 
        if (ListsockConnections[connToApply].ENCDefault) enc = Encoding.Default; 
        if (ListsockConnections[connToApply].ENCfromText) enc = Encoding.GetEncoding(ListsockConnections[connToApply].codename); 
        if (enc == null) { enc = null; } 

        // xmltextWriter = new XmlTextWriter(folderPath + "\\" + cacheFileName, enc); 
        xmltextWriter = new XmlTextWriter(DataPath + "\\_temp.xml", enc); 
        xmltextWriter.Formatting = Formatting.Indented; 

        // Start document 
        // xmltextWriter.WriteStartDocument(); 
        xmltextWriter.WriteStartElement("ConnectionList"); 
        xmltextWriter.WriteStartElement("connection"); 

        xmltextWriter.WriteStartElement("ConnectionCounter"); 
        xmltextWriter.WriteValue(ListsockConnections[connToApply].ConnectionCounter.ToString()); 
        xmltextWriter.WriteEndElement(); 

        xmltextWriter.WriteStartElement("IDConnection"); 
        xmltextWriter.WriteValue(ListsockConnections[connToApply].IDConnection.ToString()); 
        xmltextWriter.WriteEndElement(); 

        xmltextWriter.WriteStartElement("Parsed"); 
        xmltextWriter.WriteValue("false"); 
        xmltextWriter.WriteEndElement(); 

        xmltextWriter.WriteStartElement("connType"); 
        xmltextWriter.WriteValue("TCP/IP"); 
        xmltextWriter.WriteEndElement(); 

        xmltextWriter.WriteStartElement("beginConn"); 
        xmltextWriter.WriteValue(ListsockConnections[connToApply].beginDate.ToString()); 
        xmltextWriter.WriteEndElement(); 

        xmltextWriter.WriteStartElement("remoteAddressFamily"); 
        xmltextWriter.WriteValue(ListsockConnections[connToApply].remoteAdressFamily); 
        xmltextWriter.WriteEndElement(); 

        xmltextWriter.WriteStartElement("remoteIP"); 
        xmltextWriter.WriteValue(ListsockConnections[connToApply].remoteIP); 
        xmltextWriter.WriteEndElement(); 

        xmltextWriter.WriteStartElement("localIP"); 
        xmltextWriter.WriteValue(ListsockConnections[connToApply].localIP); 
        xmltextWriter.WriteEndElement(); 

        xmltextWriter.WriteStartElement("remoteport"); 
        xmltextWriter.WriteValue(ListsockConnections[connToApply].remoteport.ToString()); 
        xmltextWriter.WriteEndElement(); 

        xmltextWriter.WriteStartElement("localport"); 
        xmltextWriter.WriteValue(ListsockConnections[connToApply].localport.ToString()); 
        xmltextWriter.WriteEndElement(); 

        xmltextWriter.WriteStartElement("dataEncoding"); 
        if (ListsockConnections[connToApply].codepage != 0 || ListsockConnections[connToApply].codename != "") 
        { 
         if (ListsockConnections[0].codepage != 0) 
         { xmltextWriter.WriteValue(ListsockConnections[connToApply].codepage.ToString()); } 
         else 
         { xmltextWriter.WriteValue(ListsockConnections[connToApply].codename.ToString()); } 
        } 
        else 
        { xmltextWriter.WriteValue("NONE"); } 
        xmltextWriter.WriteEndElement(); 

        xmltextWriter.WriteEndElement(); 
        xmltextWriter.WriteEndElement(); 
        xmltextWriter.Flush(); 
        xmltextWriter.Close(); 

        tocreate = false; 
       } 
       else 
       { 
        FileInfo fi; 
        FileStream fstream; 

        //fi = new FileInfo(folderPath + "\\" + cacheFileName); 
        fi = new FileInfo(DataPath + "\\_temp.xml"); 
        fstream = fi.OpenWrite(); 

        XmlTextWriter xmltextWriter; 

        Encoding enc = null; 
        if (ListsockConnections[connToApply].ENCfromCode) enc = Encoding.GetEncoding(ListsockConnections[connToApply].codepage); 
        if (ListsockConnections[connToApply].ENCDefault) enc = Encoding.Default; 
        if (ListsockConnections[connToApply].ENCfromText) enc = Encoding.GetEncoding(ListsockConnections[connToApply].codename); 
        if (enc == null) { enc = null; } 

        xmltextWriter = new XmlTextWriter(fstream, enc); 

        xmltextWriter.Formatting = Formatting.Indented; 

        fstream.Position = fstream.Length - 17; 

        xmltextWriter.WriteRaw(" <connection>" + Environment.NewLine); 

        xmltextWriter.WriteRaw("  <ConnectionCounter>"); 
        xmltextWriter.WriteValue(ListsockConnections[connToApply].ConnectionCounter.ToString()); 
        xmltextWriter.WriteRaw("</ConnectionCounter>" + Environment.NewLine); 

        xmltextWriter.WriteRaw("  <IDConnection>"); 
        xmltextWriter.WriteValue(ListsockConnections[connToApply].IDConnection.ToString()); 
        xmltextWriter.WriteRaw("</IDConnection>" + Environment.NewLine); 

        xmltextWriter.WriteRaw("  <Parsed>"); 
        xmltextWriter.WriteValue("false"); 
        xmltextWriter.WriteRaw("</Parsed>" + Environment.NewLine); 

        xmltextWriter.WriteRaw("  <connType>"); 
        xmltextWriter.WriteValue("TCP/IP"); 
        xmltextWriter.WriteRaw("</connType>" + Environment.NewLine); 

        xmltextWriter.WriteRaw("  <beginConn>"); 
        xmltextWriter.WriteValue(ListsockConnections[connToApply].beginDate.ToString()); 
        xmltextWriter.WriteRaw("</beginConn>" + Environment.NewLine); 

        xmltextWriter.WriteRaw("  <remoteAddressFamily>"); 
        xmltextWriter.WriteValue(ListsockConnections[connToApply].remoteAdressFamily); 
        xmltextWriter.WriteRaw("</remoteAddressFamily>" + Environment.NewLine); 

        xmltextWriter.WriteRaw("  <remoteIP>"); 
        xmltextWriter.WriteValue(ListsockConnections[connToApply].remoteIP); 
        xmltextWriter.WriteRaw("</remoteIP>" + Environment.NewLine); 

        xmltextWriter.WriteRaw("  <localIP>"); 
        xmltextWriter.WriteValue(ListsockConnections[connToApply].localIP); 
        xmltextWriter.WriteRaw("</localIP>" + Environment.NewLine); 

        xmltextWriter.WriteRaw("  <remotePort>"); 
        xmltextWriter.WriteValue(ListsockConnections[connToApply].remoteport.ToString()); 
        xmltextWriter.WriteRaw("</remotePort>" + Environment.NewLine); 

        xmltextWriter.WriteRaw("  <localport>"); 
        xmltextWriter.WriteValue(ListsockConnections[connToApply].localport.ToString()); 
        xmltextWriter.WriteRaw("</localport>" + Environment.NewLine); 

        xmltextWriter.WriteRaw("  <dataEncoding>"); 
        if (ListsockConnections[connToApply].codepage != 0 || ListsockConnections[connToApply].codename != "") 
        { 
         if (ListsockConnections[connToApply].codepage != 0) 
         { 
          xmltextWriter.WriteValue(ListsockConnections[connToApply].codepage.ToString()); 
         } 
         else 
         { 
          xmltextWriter.WriteValue(ListsockConnections[connToApply].codename.ToString()); 
         } 
        } 
        else 
        { 
         xmltextWriter.WriteValue("NONE"); 
        } 
        xmltextWriter.WriteRaw("</dataEncoding>" + Environment.NewLine); 

        xmltextWriter.WriteRaw(" </connection>" + Environment.NewLine); 
        xmltextWriter.WriteRaw("</ConnectionList>"); 

        xmltextWriter.Flush(); 
        xmltextWriter.Close(); 
        fstream.Close(); 


        if (fi.Length >= (maxFileTempSize * 1000000)) 
        { 
         JoinDataFromTempFile(0, false, enc); 
        } 
       } 

       lock (lockThis) 
       { 
        hashBeginConn.RemoveAt(0); 
       } 

      } 
+3

你有沒有機會分享實際的代碼或模仿你所看到的行爲的簡單例子? – 2012-01-02 03:28:19

+2

無代碼==沒有回答 – 2012-01-02 03:31:33

回答

8

許多答案說你必須調用Dispose。雖然這些答案很好,但它們實際上並不能幫助你。您正在調用Close,並且Close和Dispose執行相同的操作。這是一個更好的練習使用「使用」塊,以便您自動爲您調用Dispose,但您的代碼仍然正常。

真正回答你的問題是「停止擔心它」。你正在考慮這個錯誤的層面。我假設你正在任務管理器中查看「工作集」或「私人字節」,但你可能不明白這些實際的含義。大多數人不會。這個答案給出了一個很好的總結:

What is private bytes, virtual bytes, working set?

OK,現在你知道什麼是「專用字節」是,它應該是比較清楚爲什麼這是沒有問題的。假設你是CLR垃圾收集器。您代表用戶分配一堆內存並將其用於存儲管理對象。垃圾收集器不時地運行,壓縮內存中的對象,並將以前由已死對象使用的內存標記爲可用。 但是,爲什麼GC將所有這些內存塊返回到操作系統? GC有證據表明,您是編寫使用大量內存的程序的人,因此它會保留空白頁面,以便在您再次使用大量內存時不必再花費分配它們從現在起兩毫秒。

所以,不要再擔心了。一切都可能很好。使用5億字節的內存不是問題。如果開始虛擬內存不足,GC可能會開始解除未使用的頁面。如果沒有 - 如果這種情況持續增長,那麼就開始擔心了。

如果您仍然擔心,請使用正確的工具進行工作。 「專用字節」很少告訴你程序中的內存實際發生了什麼。 如果您想知道垃圾收集器中發生了什麼,那麼您需要使用託管內存分析器。它會給你一個確切的事情報告。

+0

Dispose和Close不被記錄爲具有相同的行爲。請參閱[http://msdn.microsoft.com/zh-cn/library/system.xml.xmltextwriter.aspx]你有什麼證據證明它們是相同的? – 2012-01-02 23:59:13

+0

您似乎在說內存永遠不會返回到操作系統,但通過觀察私有字節,您可以看到它確實是。 (儘管可能不是全部,但他們都是這樣。)在回答你的問題「爲什麼GC會返回(內存)?」時,答案是,一個行爲良好的應用程序應該在完成使用後釋放資源。許多應用程序需要經歷一段時間需要更多內存的生命週期。對於應用程序來說,啓動時需要更多的內存,而不是以前聽說過的。 – 2012-01-03 00:20:57

+1

@ElroyFlynn你是對的,文檔沒有指出'Dispose()'和'Close()'做同樣的事情。恰好他們*做*('Dispose()'調用'Close()'如果流尚未處於關閉狀態)但是這是一個實現細節。這就是說,這是一個與答案密切相關的細節。 – dlev 2012-01-03 01:17:32

5

你應該叫xmltextWriter.Dispose()的一部分。

此外,內存不會被釋放,直到垃圾收集踢。你通常應該讓這個自動發生,但你可以使用靜態方法GC.Collect的顯式調用它()。不建議顯式調用gc.collect。讓CLR按照自己的時間表進行操作。

+0

爲@Elroy所說的 - 「按照自己的時間表」添加更多細節 - 有時GC在應用程序中使用一定量的內存之前不會啓動。對我來說,我發現在它達到〜50MB之前它什麼都不做,儘管聽起來你現在已經遠遠超過了它。 – Origin 2012-01-02 03:46:10

+1

+1:要添加:在實現IDisposable的任何事物周圍使用塊(顯然,在適當的情況下)。 – 2012-01-02 06:07:04

+0

如果沒有異常發生,OP調用'Close',那麼他爲什麼要調用等價的Dispose? '使用'顯然更好,但差異只在發生異常時很重要。手動調用Dispose肯定比手動調用Close更好。 – CodesInChaos 2012-01-02 20:25:27

0

xmltextWriter保存非託管資源,在這種情況下是一個文件,這是一個操作系統資源。除非您明確地撥打Dispose(),否則不會放棄這些資源。

最好的做法是將作家的用法放在using { }區塊中,這樣即使拋出異常也會自動調用Dispose()

Dispose()(或using)不保證內存將在該瞬間被釋放,但它確實會阻止您的應用程序保持文件打開時間超過所需時間。

相關問題