2012-01-02 15 views
0

私は、ソケット接続からデータを受け取り、データを変換し、できるだけ早くHDに格納する複雑なアルゴリズムを持っています。実際、私は、処理が遅くなることを別のスレッドを使って保存したくないのです。 データ格納アルゴリズムはこの構造に似ています。基本的に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 

それは正しく動作しますが、私はタスクマネージャの外観を取得する場合、私は私のプログラムによって消費されるメモリの量は、(500メガバイトの仕事の1時間後に)時間をかけてすぐにencreasesことに気づくことができました。これは、スレッドが入ってくるデータほど高速ではなく、.NETフレームワークが私のために一時的にすべてのメモリに格納するという事実のために正当化される可能性があります。しかし、私が理解できなかったのは、着信ソケット接続が停止しても、スレッドが動作し続ける数分後でも、タスクマネージャが500Mbのメモリを表示し続ける理由です。なぜメモリがリベースされていないのですか? XmlTextWriterオブジェクトはローカル変数であり、毎回閉じます。

要求されたよう。これは、あなたがxmltextWriter.Dispose()を呼ぶべきであるコード

 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

実際のコードや、見ている動作を模倣した簡単な例を共有することはできますか? –

+2

コードなし== no answer –

答えて

8

多くの回答で、Disposeに電話する必要があります。これらの答えはうまく意味はありますが、実際にあなたを助けません。あなたはCloseを呼び出しており、CloseとDisposeは同じことをしています。 より良い "using"ブロックを使用して自動的にDisposeが呼び出されるようにする練習がありますが、あなたのコードはそのままです。

あなたの質問に対する真の答えは、「それについて心配しないでください」です。あなたは間違ったレベルでこれについて考えています。私はあなたがタスクマネージャの "ワーキングセット"または "プライベートバイト"のいずれかを見ていると仮定しますが、それらの実際の意味を理解できないかもしれません。ほとんどの人はそうしない。これは問題ではありません、なぜそれがより明確にする必要があり、あなたが「プライベートバイトが」何であるかを知っている今

What is private bytes, virtual bytes, working set?

OK、この答えは良い要約を与えます。あなたがCLRガベージコレクタであるとします。ユーザーの代わりに多数のメモリを割り当て、管理されたオブジェクトを格納するために使用します。ガベージコレクタが実行されるたびに、メモリ内のオブジェクトが圧縮され、現在死んでいるオブジェクトによって使用されていたメモリが使用可能であるとマークされます。 しかし、なぜGCはそれらのすべてのブロックをオペレーティングシステムに戻しますか? GCには、あまりにも多くのメモリを使用するプログラムを書く人の一種であるという証拠があります。そのため、あまりにも多くのメモリを使用したときに後で再度割り当てる必要はありません。今から2ミリ秒。

だから心配しないでください。おそらくすべてが問題ありません。 5億バイトのメモリを使用することは問題ではありません。仮想メモリが不足すると、GCは未使用ページのデコミットを開始します。それがなければ、縛られずに成長し続けるなら、心配してください。

あなたがまだ心配している場合は、そのジョブに適切なツールを使用してください。 「プライベートバイト」は、実際にプログラム内のメモリで実際に何が起こっているかをほとんど知らせません。 ガベージコレクタで実際に何が起こっているのかを知りたい場合は、マネージメモリプロファイラを使用する必要があります。それはあなたに何が起こっているのかを正確に報告します。

+0

DisposeとCloseは、同じ動作をするように文書化されていません。 [http://msdn.microsoft.com/en-us/library/system.xml.xmltextwriter.aspx]を参照してください。同一であるという証拠は何ですか? –

+0

あなたはメモリが決してOSに返されないと言っているようですが、プライベートバイトを観察することによって、確かにそれが見えることがわかります。 (なぜ、GCが(メモリ)を返すのでしょうか?)あなたの質問に答えて、答えは、正常に動作するアプリケーションが実際にそれらを使って終了したときにリソースを解放するということです。多くのアプリケーションは、ある時点で他のメモリより多くのメモリを必要とするライフサイクルを経ています。起動時にアプリケーションが後でよりも多くのメモリを必要とすることはあまり知られていません。 –

+1

@ElroyFlynn正しいですが、ドキュメントには 'Dispose()'と 'Close()'が同じことを示すものはありません。ストリームがまだ閉じた状態でない場合、 'Dispose()'は 'Close()'を呼び出しますが、それは実装の詳細です。それは、答えに密接なディテールだと言われています。 – dlev

5

の一部です。

ガベージコレクタが起動するまで、メモリは解放されません。通常、自動的にこの処理を許可する必要がありますが、静的メソッドGC.Collect()を使用して明示的に呼び出すことができます。 gc.collectを明示的に呼び出すことはお勧めしません。 CLRがそれを自分のスケジュールで実行させる。

+0

@Elroyが「独自のスケジュールで」と述べたものにさらに詳細を追加する - アプリケーションで一定量のメモリが使用されるまで、GCが起動しないことがあります。私の場合、私はそれが〜50MBに達するまでは何もしないことを発見しましたが、あなたが現在それをはるかに上回っているように思えます。 – Origin

+1

+1:追加する:IDisposableを実装するものの周りのブロックを使用してください(そして、必要に応じて、明らかに)。 –

+0

例外が発生しなければOPは 'Close'を呼び出します、なぜ彼は同等の' Dispose'を呼び出さなければなりませんか?明らかに 'using'が優れていますが、例外が発生した場合にのみ違いがあります。そして手動で 'Dispose'を呼び出すことは、手動で' Close'を呼び出すことよりも優れています。 – CodesInChaos

0

xmltextWriterがあります。の管理対象外のリソースリソース(この場合はオペレーティングシステムリソースです)。あなたが明示的にDispose()を呼び出さない限り、これらのリソースを放棄しません。

ライターの用途をusing { }ブロックに囲んで、例外がスローされても自動的にDispose()が呼び出されるようにすることをお勧めします。

Dispose()(またはusing)は、メモリがその瞬間に解放されることを保証するものではありませんが、アプリケーションが必要以上にファイルを開くのを妨げます。

関連する問題